* Preserve native model choice when restoring ACP chats
* Forward startup observations through the OpenCode connection
* Use fixed time in the connection regression fixture
* Complete the model-command fixture session identity
* fix(dictation): keep the last word when dictation stops
Streaming models got no trailing audio before inputFinished, so the
encoder never saw the lookahead frames it needs to emit the final word.
Pad 0.66 s of silence at stop, as sherpa-onnx's own decoders do.
The renderer also tore the mic down the instant stop was pressed,
dropping the unread processor buffer. Keep capturing 250 ms after a
user stop before closing the stream.
* refactor(dictation): let the stop tail rely on the capture generation check
* refactor(dictation): keep the capture hook's stop-tail import on one line
* fix(dictation): leave a session an error tore down during the stop tail
* perf(runtime): cache OMP and Grok model discovery
* perf(runtime): share a slow model probe for its whole timeout
* refactor(runtime): key and probe model discovery from one input
The streaming worker posted the current hypothesis after every 100 ms feed,
so desktop IPC and the phone's text version churned about ten times a second
with unchanged text. A 5 s clip now sends 11 partials instead of 42.
* refactor(agent-session): share the model-snapshot rules with the phone
Move the pure snapshot selection and record rules, the account settings that make held lists stale, and the saved-only preload decision into src/shared so the phone can seed its model picker from the same rules. The renderer keeps its per-host store and sync.
* refactor(agent-session): tidy the shared snapshot rules
* perf(runtime): stat the device registry at most once a second
* test(runtime): restore real timers after each revocation test
* test(runtime): drop the registry read-count test
* refactor(runtime): trim the registry throttle comments
* fix(runtime): pairing and delegation planning read the device file unthrottled
* perf(agent-session): stream chat text as appends
* perf(mobile): read text-append support from the connection's status answer
* perf(mobile): open the chat stream once the host's append support is known
* refactor(mobile): seed text-append support from the shell's status
* fix(agent-session): stop asking for appends after one is refused
* perf(mobile): seal and decode socket frames through native bindings
* refactor(mobile): decode base64 socket messages with the canonical primitive
* refactor(mobile): share the canonical base64 decoder with socket payloads
A new streaming stream starts with empty encoder caches, and zipformer
en-20M then drops most of the first second of speech: the first word was
wrong on 71 of 73 LibriSpeech clips. Each session's stream now takes a
second of silence before its first audio. That cuts per-utterance WER from
27.0% to 16.1%. The priming runs on the first feed so stop never waits for it.
Offline models decode the whole utterance after stop, so their thread count
is the user's wait. On the shipped sherpa-onnx, 4 threads cut a 5 s
utterance from about 190 ms to 122 ms with the same transcript and memory.
The recognizer configs move from stt-worker.ts into stt-worker-model-config.ts
so the worker has room under its line cap.
* fix(emulator): distinguish used and unavailable devices in picker
* fix(emulator): retain older usage timestamps and English review fixtures
* Share emulator recency metadata and valid-selection guard
* Align PR 36548 with current checked types and component contracts
* fix(i18n): remove keys from replaced controls
* fix(emulator): reset picker search and keep retries usable
Clear the picker search after choosing a device and keep Connect available
when the host should choose its default device on a retry.
* ci: refresh emulator picker checks after main repairs
---------
Co-authored-by: Kelvin Amoaba <97001695+AmoabaKelvin@users.noreply.github.com>
terminal.subscribe accepts capabilities.outputAck and echoes outputAck with a device-bound streamToken. Output beyond a fixed 512 Ki-unit window waits for terminal.ackOutput; held output past the pending budget is replaced by one recovery snapshot once the link drains.
* feat(mobile): let the host page open a target inside its own document
* fix(mobile): skip a duplicate open, re-render the stack only for a waiting route
* fix(mobile): resolve the open target through Expo and open a target that changed before mount
* test(mobile): keep Back in one open-target case
* refactor(mobile): hold routes under the top with one released flag
* refactor(mobile): own the navigator ready listener in the effect
* fix(mobile): leave single-route stacks drawn from the start
* fix(terminal): report focus-out to ?1004 programs when their last viewer leaves
A viewer that vanishes (laptop sleep, dropped link, app quit) never sends the
ESC [ O its xterm would send on blur, so programs that armed focus reporting
kept believing they were focused. The daemon now remembers the last focus
report each PTY heard and sends one ESC [ O when its last client detaches.
orcad asks it to when the last device that viewed a PTY disconnects; a
resubscribe from a still-connected device is not a departure. A daemon that
predates the request rejects it, and the adapter stops asking that client.
Fixes#28350
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(terminal): keep the daemon router under its line cap and justify focus-loss test casts
Refs #28350
The subscribe-buffer test now expects the viewer device argument.
* fix(terminal): let a hidden remaining pane yield focus-out on device departure
Refs #28350
Build on main's pane-visibility signal: a remaining remote view whose
pane is hidden already blurred, so it no longer holds back the focus-out
for a departed device. Views that cannot report a hidden pane still do.
---------
Co-authored-by: Claude <noreply@anthropic.com>
* fix(remote): let Remove drop a managed server saved under two SSH aliases
When one managed SSH server was saved twice, Settings said to remove one
entry, but Remove refused any pairing that has a managed deployment. When
another saved entry still manages the same server (same host key), Remove now
unlinks this entry through the managed forget path: it closes this entry's
tunnel and releases its SSH claims without contacting the host, so the server,
its projects and live terminals stay with the other entry. A managed server
with no other managing entry keeps the guard.
Fixes#38604
* fix(remote): recheck the managed twin inside the lifecycle queue
Codex review: a Remove queued behind another lifecycle action could forget
the last managed entry if the twin was removed meanwhile, and the twin match
compared raw Base64 text. Removal now goes through a forgetRedundant action
that re-finds the twin inside the target's lifecycle queue and unlinks in the
same tick, and matches host keys with the canonical matcher.
Refs #38604
* test: cover redundant managed removal after the dispatch suite was removed
Refs #38604
A recipe VM workspace runs on its VM's own Orca server, so a phone, the CLI or
the desktop reaching it while the VM slept dialed a server that was not there
and failed. Only the host window's click ran the recipe's resume.
- The VM wake owner (WorkspaceSleepCoordinator) tracks the VM operations it
was asked for and answers where the VM stands: a pending wake or a running
suspend outranks the stored record.
- The host holds a request that opens the workspace (worktree.activate,
defined once in shared code) until the VM is up: three minutes for the
desktop and the CLI, and for a phone only as long as still lets the relay
connect inside the phone's 30-second deadline. A VM still up keeps a sleep
on its way from suspending it; a VM asleep or suspending wakes after what is
running, joining a wake already pending. The open answers waking only when
the hold runs out, wake_failed when the wake fails, and asleep when a Sleep
asked for while it was held won; that open then wakes nothing more. Other
requests answer waking or asleep instead of dialing nothing. A Sleep asked
for during a wake keeps its place in the lifecycle queue and starts once the
wake is done. A caller that gives up stops waiting and frees its queue
place; the wake goes on.
- An open of a server the user disconnected is refused before anything wakes
its VM, and cancelled if they disconnect while it waits. A wake carries the
SSH host's user hold from when it was accepted and every Disconnect since,
so its connect never lifts a hold; the VM still resumes and its new SSH
address is saved for the user's own Connect.
- A wake re-pairs a paired VM's server. The request that waited for it is
held to its caller's pairing as of before the wake (a stale caller is
refused before it can wake anything), then to exactly the pairing revision
the resume produced (including a re-pair its SSH reconnect made), whatever
process now serves it; any other change still
refuses it. A phone link still preparing for an open survives only the
re-pair its own wake made; any other retirement, or a user Disconnect, ends
it, and a link preparing for anything else is retired at once.
- The hold lives in the desktop's environment preparation, which its own calls
and subscriptions, the phone relay and the CLI all go through. A phone open
on a link to a server whose VM is not up gets a fresh link; the old link's
requests are answered waking or asleep. Further opens join a link already
waiting on the wake. A phone link's whole open (server preparation with any
hold, grant sync and the socket) shares one deadline inside the phone's
own, for every server.
- The CLI dials a VM directly, so `orca worktree activate` asks the desktop
(runtimeEnvironment.wakeRecipeVm) to open the VM and reads the server's
pairing again; the refusals (including runtime_manually_disconnected) keep
their codes over RPC, and a host without recipe VMs answers that one RPC
with method_not_found. Hosts that do this advertise
host.recipe-vm-wake.v1.
- A workspace this host runs on a recipe VM over its SSH target wakes on this
host's own activation, through the resume's explicit connect
(wakeWorkspaceVm -> resumeVm -> connectRuntimeOwnedSshTarget). That connect
runs whenever the VM is in SSH mode, even when its recipe had no resume step,
since suspend tore down the transport.
Fixes#36923
Co-authored-by: ggbdpq <ggbdpq@gmail.com>
* fix(terminal): end tail lines at CR CR LF instead of reading them as empty
Raw-mode programs end lines with CR CR LF. The output normalizer folded only
the CR directly before LF, so the leftover CR made each completed line read
as the empty text after it, and terminal.read returned blank lines. A run of
CRs lands on the same column as one CR, so treat the whole run before LF as
part of the line ending.
Fixes#38667
* chore: shorten the CR run comment
Refs #38667
* fix(terminal): defer CR until kept output decides it
A CR followed only by discarded escapes and then LF (text CR SGR CR LF)
still read as an empty line, and a restore cut landing just before CR CR LF
seeded a blank first row. The normalizer now holds each CR until the next
kept output: before LF it ends the line, and runs or escape-split CRs act as
one. The restore anchor skips a whole CR-run line ending.
Refs #38667
* test: size the restore-cut case from the exported seed limit
Refs #38667
* fix(files): open a granted host file the way a workspace file opens
A plain click on a host file outside every workspace opened it in the
editor through the grant's whole-file text read, so a video, a large
image or any text past 512 KiB failed with "too large to open from its
host". Granted files now go through the same reads as workspace files:
media streams to its viewer by range, images and PDFs page past one
reply, and large text pages into the editor. A host file is addressed
either by workspace path or by its grant, and the host gains
files.statTerminalArtifact to pair with files.readTerminalArtifactChunk.
The host names a large binary as binary before refusing its size, as
files.read does, and a streaming player renews a lapsed grant the way
the editor's reads do. Hosts without these methods answer
method_not_found, which the paged reads already turn into an
update-the-host message.
Refs #35968
# Conflicts:
# src/main/media/media-preview-protocol.test.ts
* fix(files): page a granted binary with the grant that served it
A content read renews a lapsed grant without telling the tab, so a bytes
editor paged the file with the dead grant and failed on every reload. The
read now reports the grant that served it; the bytes editor uses that grant
and the tab keeps it, as a save that renews one already does.
Refs #35968
* fix(files): renew a granted preview on every host call and keep unsavable grants read-only
Review: renewal ran only before a media response returned, so a grant that
lapsed under a streamed chunk or a pdf.js range read over IPC failed instead.
Every host call for a remote preview now goes through one helper that renews a
lapsed grant once. A grant saves only text within one write, so a granted
binary or text past 512 KB now opens read-only instead of failing to save.
Refs #35968
* fix(editor): show an unsavable granted copy read-only in every view
Review: read-only reached only the edit surface, so a large granted notebook
or markdown file still opened its editable rich view. The editor panel now
treats the copy as a read-only tab, so rich views fall back to the raw source
view as they do for other read-only tabs. A renewed read-only grant also reads
as read-only and stays off the tab.
Refs #35968
* fix(files): renew a granted bytes read whole and never splice versions mid-stream
Review: a bytes editor opened after its grant expired kept failing, since its
paged read never renewed. It now renews and restarts the whole read. A stream
or PDF range that renews mid-read now continues only if the renewed grant sees
the same file version, so a rewritten file can't splice into one response.
Refs #35968
# Conflicts:
# src/main/media/media-preview-protocol.test.ts
* fix(files): keep each preview response on its own grant and pin a bytes read's pairing
Review: a stream crossed to a grant another request had renewed without
checking the file version, and a bytes read that renewed during a re-pair
could read from the new host. Each response now keeps the grant it started
on and moves to a renewed one only after checking the version it serves, and
a bytes read pins its pairing before the first call.
Refs #35968
* fix(files): bind a preview's stat to the grant that saw it
Review: a stat cached from the old grant could start a response on a grant
another request had just renewed onto a rewritten file. The cache now keeps
each stat with the address that produced it, a response starts on that
address, and a renewal checks the version by stating the renewed grant
itself.
Refs #35968
* fix(files): keep a pinned read's pairing on its paged address
Review: the paged-read address dropped a caller's pinned pairing, so a re-pair
between a grant renewal and its retry could send the retry to the new host.
The address now carries the pinned revision.
Refs #35968
* test(e2e): give the granted video spec's timeout its reason
Refs #35968
* test(media): keep the granted preview renewal tests in their own file
Main trimmed media-preview-protocol.test.ts to local previews, so the tests
for renewing a granted preview's lapsed grant (burst, streamed chunk, rewritten
file, PDF range over IPC) now live in media-preview-protocol-granted.test.ts.
Refs #35968
* feat(cli): add orca host rm for saved SSH targets
orca host rm --host ssh:<target-id> calls the runtime RPC ssh.removeTarget,
the same removeSshTarget the Settings UI reaches, so the tombstone keeps the
passive ~/.ssh/config import from adding the alias back.
Also document how the import treats Match blocks and Include files.
* fix(ssh): clear a removed target's live state and rename in main for every removal path
Removing an SSH target through ssh.removeTarget (orca host rm, paired clients)
left open tabs with stale reconnect state and kept the host's rename, because
only the Settings dialogs cleaned up after their own IPC call. The shared
removal mutation now drops the display-label override and tells the renderer,
which clears the target's state once for all callers.
Fixes#37949
* fix(ssh): clean up after a removed target in the teardown every removal ends in
A recipe VM's cleanup removes its SSH target through removeRegisteredSshTarget
directly, so the window kept that target's live state. The broadcast and the
rename drop now run there, after the target is gone.
Fixes#37949
* test(cli): keep host rm's retarget-flag refusal next to its other cases
Its old file was removed on main.
Fixes#37949
* refactor(cli): give the host, managed-server and VM handler groups their own module
Keeps the handler manifest under the file-length limit.
Fixes#37949
---------
Co-authored-by: Florin Timbuc <florin@sowild.design>
* fix(sidebar): keep the selected card's host pill outline visible in dim themes
#38841 tinted the host pill outline 40% of the sidebar text into the
sidebar. A theme whose sidebar text is only 4.5:1 leaves that outline at
about 1.6:1 against the selected wash, which matches the pill's fill, so
the pill loses its shape.
When an app theme is painted, its colors are now concrete, so compute
once per theme the smallest mix (from 40%) that gives the outline 2:1
against the selected wash, the same floor focus rings use, and paint it
as --worktree-host-pill-outline-mix. main.css falls back to 40%, so
Orca's built-in themes and any theme bright enough keep today's look.
The tinted sidebar resets it, like the row wash. The wash's CSS fallback
joins the fallback table so the check (and the token reference) read
what main.css paints.
Refs #38641
* fix(sidebar): floor the host pill outline in the tinted left sidebar too
The tinted sidebar paints the app's text on its tint mixed into the app
background, so the theme's measured outline mix doesn't apply there and
it fell back to 40%: a dim theme (#919191 on #2a2a2a) at the default 8%
tint left the outline at 1.6:1 on the selected wash. Measure the tinted
colors once whenever the app theme or tint settings change, paint the
result as a root variable, and have the tinted sidebar read it. Share the
measurement (hostPillOutlineMixOver) with the theme path, and make its
comment name the actual invariant instead of the pill label's contrast.
Refs #38641
* refactor: group structured session modules by owner
* test: retire status history work-count oracle suite
* refactor(main): organize journal storage and projection owners
* Consolidate restart recovery fixture imports
* Consolidate concrete session option model imports
* fix(cli): keep read-only commands working when environment usage can't be recorded
The CLI recorded each environment's last-used time with a strict store write,
so a profile whose directory refuses chmod (EPERM) failed commands whose reply
had already arrived. The desktop already skipped such failures in one path.
Move that best-effort recorder to shared code and route every desktop and CLI
usage write through it.
Fixes#38673
* test: assert the usage write failure, not call counts
Refs #38673
* test: skip the chmod EPERM case on Windows and drop a cast
Refs #38673
* fix(terminal): a host with a window keeps a pane a client moved to a new tab
Dragging a split pane onto the tab strip in a paired worktree whose host runs
the desktop app with a window flickered and snapped back. The client draws the
new tab and calls session.tabs.movePaneToNewTab, but the host answered
not_held whenever it had a window, because the window owns the layout and only
headless hosts committed the move. The client reverted, and even without the
revert the host window's next snapshot would have rebuilt the old tab.
Main now asks its window to make the move and waits for the answer, the way
other client requests reach a window-owned host. The window moves the pane
with its own drag-out path under the tab id the client already drew, at the
client's drop position, mounting a parked source tab first. A pane the window
cannot reach is refused, so the client puts it back; a host without the
window bridge still answers not_held. Older clients and hosts are unaffected.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(web): rely on the optional pane-move bridge instead of no-op stubs
The web client never receives host pane-move requests, and the bridge
already skips registration when these members are absent; dropping the
stubs keeps web-ui-api.ts under the line limit after rebasing on main.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(e2e): a window host keeps a pane a paired client moved to a new tab
The window-host case asserted the old refusal, where the client drew the new
tab and put the pane back. It now drags a pane out on a paired client and
checks the pane stays in the tab the client drew: the host window holds the
leaf alone under that tab id, no snapshot pulls it back, and the source keeps
one pane. It fails on main, where the tab count falls back after the drop.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(terminal): refuse a pane move the host window cannot answer
When a paired client asks a host with a window to move a pane to a new
tab, the host relays the request to that window. If the window is gone,
closes, or does not reply within 10 seconds, the relay rejects. The
host returned that rejection as an RPC error instead of a move result.
The host now answers { status: 'refused', reason: 'pane_unavailable' }
in that case. The client already puts the pane back on a refusal, and
this is the reply the relay timeout was sized for.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(terminal): fence a window's pane move once the client heard it timed out
The relay told the client "refused" after 10s but left the window's move
running, so a late commit moved the pane on the host after the client had
put it back. Main now fences the commit: a move the client was told timed
out commits nothing, and a commit answers the client at once, before the
deadline can turn it into a refusal.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(terminal): keep the pane-move fence Electron-free and let a claimed commit answer
The leaf-move IPC is shared with the plain-Node runtime, so the fence moves to its own
Electron-free module. A window that goes away mid-commit no longer refuses a move its commit
landed, and a second move cannot replace a fence a timed-out move still holds.
Fixes#37082
* chore(terminal): follow moved shared modules after rebasing the pane-move relay
Refs #37082
* fix(terminal): hold a client's pane move's source tab mounted until the move settles
The timed split-mount lease could expire while the window was still moving the
pane, so cold parking could unmount the source tab after main had already told
the client the move landed. The move now holds the tab mounted for its whole
duration and releases it when it settles.
Fixes#37082
* fix(terminal): don't toast the host window for a pane move another client asked for
Fixes#37082
* fix(terminal): relay a client's pane move only to a window that owns the layout
Where main owns the layout (the dark ORCA_LAYOUT_OWNER=main path), the window's
move goes back through main, which names its own tab, so the client's tab id
could not be kept. Main answers not_held there, as before this change.
Fixes#37082
* fix(terminal): name the renderer a relayed pane move belongs to
Fixes#37082
---------
Co-authored-by: Seunghwan <hyunsh.cycle@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* feat(antigravity): report last-known quota for every saved account
agy has one shared login, so Orca never switches it to read another
account. Each successful usage read is now verified against the native
login before and after the fetch, attributed to the matching saved
account, and kept in the vault per runtime with its original read time.
A login change mid-read discards the reading. Settings, the status bar
usage popover, and orca account list --json show each saved account's
last reading, or unknown when it was never read.
Fixes#31664
STA-11623
* chore(antigravity): add saved-account quota copy and status bar fixture
* fix(antigravity): clear the sign-in hold when agy signs in again to the same account
Comparing logins by Google subject meant a fresh sign-in to the same
account never reported a credential change, so the meter stayed on
"Sign in with agy". A new refresh token now counts as a change; agy's own
token refresh keeps the refresh token and still doesn't.
* test(antigravity): attribute a WSL runtime's reading to that runtime's saved accounts
Antigravity launched in a WSL guest reads ~/.gemini/antigravity-cli/settings.json
inside the distro, but trust preflight skipped every non-Claude WSL launch, so
first-launch agy workers stopped at the trust menu. Write the guest's Linux
path into the distro home's settings (through its cached UNC home), and record
ownership under the host workspace path so worktree removal prunes it.
STA-8154 (CR-P2-002)
Per-pane terminal zoom lived in a ref owned by a single TerminalPane mount
and keyed by the runtime pane id, so any remount (hidden-tab parking, the
former Agents view) dropped it back to the global font size.
Store the override in a session-only map keyed by the durable leaf id and
make it the only per-pane font size store. The zoom handler and the
appearance pass read it by leaf id, and it is cleared on a real pane close
or when the tab is gone at mount cleanup, so detached/moved leaves keep
their zoom.
Co-authored-by: Neil <neil@stably.ai>
* Show workspace and branch identity below the chat composer
* Use chat context for composer workspace identity
* Read composer hosts from unified tab records
* Keep composer behavior fixtures focused on input flows
* fix: reuse guarded workspace reader in chat footer
* fix(chat): preserve folder identity and composer focus ring
* Show machine and workspace identity below the chat composer
* Avoid unrelated host focus invalidating composer identity
* Correct composer context and runtime fixture types
* Isolate machine-name lookup in composer flow fixtures
* Simplify composer submission bindings
* Keep the composer session options result together
* Match the composer machine icon to the sidebar
* Keep composer types and session options in their owning modules
Paired clients now publish the chat actually selected on the desktop as the active tab; saved layouts, CLI-created chats, closes and restarts keep it consistent. Carries community PR #34526.
Co-authored-by: Jurassic Knights <jurassicknights@gmail.com>
When Orca's local-account runtime is WSL on Windows, the Antigravity usage
meter still ran the host `agy`, so it showed the wrong account or "not
installed". Route the probe through runWslProcess for the selected distro
(never booting a stopped one), key the unsupported-CLI latch per runtime,
tag readings with the runtime as provenance, and drop another runtime's
last reading instead of keeping it as stale. Settings changes retarget
the fetcher and reread usage.
A WSL target without a distro now names the default through
resolveWslDefaultDistro (registry DefaultDistribution) rather than
listWslDistrosAsync()[0], which skips docker-desktop, falls back to
registry order, and caches the list for the process lifetime.
Ported from #31542 onto current main: reuses main's antigravity fetch
generation (#34165) instead of adding a second one, follows moved WSL and
provider-account-services paths, and keeps only the tests that cover the
new behavior.
Co-authored-by: CAVIN <35207870+zzz163519@users.noreply.github.com>
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
* fix(codex): remove Orca-created pre-trust entries when a worktree is removed
Records which [projects."<path>"] tables Orca's preflight trust created in a
managed Codex config (with the exact bytes written), and on worktree removal
deletes only those, inside the existing trust-config mutation queue. Removal
paths await the purge so a removal is never reported before the entry is gone.
Ported from #24803 (commits 88d5469c, c1ffc5a4, 11b0bd74, f85606b3) onto
current main: conflicts resolved, stray re-export wrappers dropped, and tests
trimmed to AGENTS.md rules (ordering/timing, private-state, Cartesian and
lower-layer duplicate cases removed).
Co-authored-by: Neil <neil@stably.ai>
* fix(antigravity): drop Orca-added trustedWorkspaces entries on worktree removal
Generalizes the Codex pre-trust ownership ledger into a small factory
(agent-trust-ownership-ledger.ts) and uses it for agy: when Orca appends a
worktree path to ~/.gemini/antigravity-cli/settings.json trustedWorkspaces, it
records the exact entry, and worktree removal removes only that recorded entry.
Entries that already existed before Orca's grant are never recorded or removed.
* fix(trust): keep folder-workspace trust on session removal; isolate trust test userData
Only checkout-deleting removal paths drop Orca-created agent trust now.
Folder-workspace sessions and forgotten orphans leave the directory on
disk, so removing one must not strip the grant siblings still rely on.
Also point the execution-host trust test at a temp userData so the new
ownership ledger never writes to the real Orca config, and make the e2e
removeWorktreeMetadataAndHistory stub return its Promise.
---------
Co-authored-by: ggbdpq <ggbdpq@gmail.com>
* fix(antigravity): switch agy accounts through the Linux Secret Service keyring
agy stores its Linux login with go-keyring's Secret Service provider
(service=gemini, username=antigravity, login collection or default alias)
and falls back to its credential file without a session bus, in containers,
SSH and WSL. Add a secret-tool/gdbus adapter that mirrors that collection
choice, refuses locked keyrings with a clear error, and keep the file store
for headless hosts.
Fixes#32818 (STA-11911)
* test(antigravity): avoid casts in Linux keyring adapter test
Share one language-aware unicodeHighlight builder across the file editor,
the standalone diff viewer, and combined diff sections. Markdown skips
ambiguous-character highlighting so full-width punctuation no longer
triggers the warning banner; invisible-character detection stays on
everywhere. includeStrings is pinned to true because Monaco otherwise
resolves it to false in trusted workspaces.
Fixes#33860
Co-authored-by: QTom <qt@truesightai.com>
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
An ACP agent's TMPDIR sat inside the data folder. On macOS that path made
a socket such as datacloud-mcp-dataAgentKit-antigravityide.sock 131 bytes
long, over the 103-byte limit, so child programs could not bind it.
When a socket under the data-folder root would not fit, use a short
per-user folder in /tmp (mode 0700, owner checked via ensureOwnedPrivateDir,
keyed by a hash of the data root so Orca copies never wipe each other), and
clear the old data root once. Roots that fit, and Windows, keep the current
behavior.
Ported from #33948 onto current main (acp-private-temp now uses
launchPreparationFailure; daemon-socket-endpoint-path moved under
daemon/endpoint/publication; the launch-parity test it touched was removed).
Co-authored-by: Manan Chataut <thefrikidude@thefrikidude.local>
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
* feat(cli): select and remove any saved agent account from `orca account`
`orca account select` and `orca account rm` accepted only OpenCode and
Devin. They now cover every provider with saved accounts — Claude, Codex,
OpenCode, Devin and Antigravity — through the runtime methods the
status-bar switcher and Settings already use (accounts.selectClaude,
selectCodex/selectCodexForTarget, selectData, antigravitySelect and the
matching remove methods). No runtime or wire change.
`--account` takes an id, an email/label (case-insensitive) or `system`.
A name shared by several accounts is refused with their ids rather than
guessing which subscription to bill. `system` is refused for Antigravity
(no system default), for Claude from the WSL bridge (the RPC has no
target and would reset the Windows host), and always for `rm`.
`orca account list` now prints each account's id and a `system` row,
accepts `--agent` for every provider, and adds the Antigravity block when
the host can read it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(cli): assert the host refusal for Antigravity accounts from WSL
The host rejects every client-selected WSL target for Antigravity account
management, reads included, so the test now mirrors that refusal and checks
that no select call is made instead of asserting an impossible success path.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(cli): keep only the account-selection tests that guard this change
Moves the guards into account.test.ts (the handler layer that owns them) and
drops layer-duplicating, copy-pinning, Cartesian and mock-only cases per
AGENTS.md test rules; un-exports resolveAccountId (test-only export).
---------
Co-authored-by: Maxime AUBURTIN <m@hellomax.io>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(runtime): fail agent readiness fast when the program reports a sign-in block
agy shows its login menu when signed out and reports OSC 7501
state=blocked:kind=auth. tui-idle treated that as pending, so worker-start
waited out its whole readiness timeout and reported a vague
'Agent did not become ready'. Rank a fresh program sign-in block as a
blocked verdict (agent-sign-in-prompt) so worker-start fails at once with
Agent startup blocked: agent-sign-in-prompt and never types the task into
the login menu.
Fixes#37056 (STA-13300)
* fix(runtime): require an agy sign-in block to persist before failing readiness
agy flashes its sign-in splash at startup and then signs itself in (#28348), so a fresh OSC 7501 blocked kind=auth is not yet final. Hold the verdict pending for 3s from the first auth report (repeats keep the first stamp; idle/working supersede it) and recheck when the window ends.
* feat(github): filter Tasks PRs by state and by who, like GitLab MRs
GitHub PRs in Tasks get the same two chip groups as GitLab MRs: state (Open, Merged, Closed, All) and who (Everyone, Mine, Reviewing). The chips read and write the search query, so labels and typed text survive a click and nothing new is saved. A combination equal to one of the old presets is applied as that preset, so saved views, prefetch and the phone see the same strings as before.
Tracked in STA-14084.
* fix(github): keep right-click on Open saving the open-PRs default view
* fix(github): wrap the PR state and who chips as two groups
* feat(native-chat): show details on link cards for any repo on a known host
A chat link card for a pull request or issue in a repository other than the
workspace's own showed only its name, because the lookup answered only for the
workspace's configured remotes. Previews now read any repository on a host those
remotes use, with that host's sign-in, as the common pattern does. Other lookups
keep the exact-repository check, and an unknown host still gets no credentials.
* fix(native-chat): open link cards for other repos on the chat repo's host
The hover card still admitted only the chat repo's own links, so the wider
lookup was never reached. Links to any repo on a host the chat repo uses now
open the GitHub card. When an older host or a repo the sign-in can't read
leaves it unanswered, the card falls back to the web preview, or just the
link's name, as such a link showed before, instead of a failure.
* fix(native-chat): keep another repo's web preview until its details arrive
A link card for another repo showed the GitHub skeleton first and only fell back
once the lookup failed, so older hosts got two loading stages and a change of
shape. It now shows the web preview it always showed until the details arrive,
and keeps it when none do.
* fix(native-chat): show just the name for another repo's link while its details load
With web previews off, a link card for another repo showed the GitHub skeleton
and collapsed to the name when no details came. It now shows the name from the
start, so nothing collapses when an older host or an unreadable repo answers
with nothing.
* feat(native-chat): show a card for pull requests a chat turn opened
When a turn's own command runs gh pr create and prints the new URL, the chat
shows an "Opened orca#3" card under that turn with the PR's state, title and
changed lines, read live from GitHub. The eye-slash control hides the card kind
and a toast links to the new Settings switch.
* fix(native-chat): satisfy lint in the opened pull request card
* fix(native-chat): keep opened pull request cards through tool runs and failed rereads
The card now rides a turn's work run, a clipped create output is always read
whole (retried when the chat is shown, never while hidden), older Codex JSON
output is decoded, rereads keep the last answer and restart past an in-flight
read, failing lookups back off, and a failed hide save says so.
* fix(native-chat): detect pull requests Codex opens through PowerShell, and wait for clipped output
Codex on Windows runs commands as pwsh -Command '...', which detection now
unwraps (and cmd /c), with tests on Claude's and Codex's recorded calls. A
clipped create output is decided from its whole text, each message is scanned
once, rereads keep their bytes counted, a merged card rereads after an edit,
and the header names another repo's pull request in full.
* fix(native-chat): retry each clipped pull request output until its host answers
Each create output cut short on the wire keeps its own backoff while the chat is
visible; a host whose support is unknown stays pending, and only one that says
it can't give outputs whole is decided from the head. PowerShell options and
backtick escapes are read as PowerShell does.
* fix(native-chat): read PowerShell create commands in PowerShell's own quoting
Decoding a tool call's script moves to its own module. PowerShell launches are
lexed with its quoting (single quotes keep backticks literal, double quotes and
bare text escape with them, here-strings and comments are text) and launch
options follow the common pattern's tables; what can't be read whole opens
nothing. A cancelled retry no longer records a failure.
* fix(native-chat): decode a launch wrapper inside a PowerShell tool call
* fix(native-chat): read Codex's escaped quotes in a Windows PowerShell command
Codex on Windows writes a double quote inside a double-quoted -Command as \",
so a create with an apostrophe in its title was skipped. Tests use the three
calls recorded from Codex on Windows.
* fix(native-chat): read a PowerShell launch line in the quoting of what ran it
Codex joins argv in POSIX quoting even on Windows, splitting one word into
differently quoted pieces, so a script ending in a backslash or holding both
$ and an apostrophe showed no card. The launch line now goes through the same
POSIX word decoder as the login-shell preview, and a PowerShell tool's own
line through PowerShell's quoting.
* fix(native-chat): find a PowerShell or cmd launch anywhere in a command list
A Bash call such as `pwsh -Command 'gh pr create --fill' && echo done` lost its
card once launch lines were read as POSIX words, and Codex's joined
`cmd.exe /c 'script'` never had one. Each command in a POSIX list is now read on
its own, through one launch reader shared with argv, while Node's Windows
`cmd.exe /d /s /c "script"` form keeps cmd's own quoting. PowerShell lexing
moves to its own module.
* fix(native-chat): unwrap a PowerShell or cmd launch only when it is the whole line
Rebuilding a command list around a nested launch could pull one out of a comment
or heredoc into a false card, and an unreadable launch hid a real create beside
it. As the common pattern does, only a line that is one launch is unwrapped;
any other line is analyzed as written. A PowerShell tool's line and Node's cmd
form must likewise be a single launch.
* fix(native-chat): unwrap cmd and PowerShell-tool lines only when they are one launch
Node's cmd form now unwraps only a /c script that is one quoted string with no
quote inside, since cmd escapes none, and a PowerShell tool's line ends at a
bare line break. Text after either launch can no longer pass for its script.
* fix(native-chat): read a PowerShell line continuation as a word break
A backtick before a line break in a PowerShell tool's line joined the next line
into the current word, so an argument on the next line could pass for a
command after the launch.
* fix(native-chat): unwrap only the launch shapes agents are recorded writing
Hand-written readers for cmd launches and for a launch nested in a PowerShell
tool's script kept letting printed text pass for a create. Only argv, a shell's
whole -c line and Codex's Windows pwsh -Command line are unwrapped now; argv is
never space-joined, and detection reads a shell line as whole POSIX words rather
than through the preview's lenient prefix. cmd launches and nested launches are
intended misses until an agent is recorded using them.
* fix(native-chat): read an escaped separator as text when finding a create
An escaped \; stayed in the analyzed commands and passed for a separator, so
printf '%s\n' \; gh pr create showed a card though only printf ran. Escaped
characters are now text, like quoted strings and comments.
* fix(native-chat): remove a line continuation when finding a create
Blanking escapes also turned a backslash-newline into a word, so a create on
the line after a continuation no longer started a command and lost its card.
A continuation is now removed, as the shell removes it.
* fix(native-chat): treat only backslash-LF as a line continuation
Bash removes a backslash before LF but not before CRLF, where the backslash
escapes CR and LF still ends the command. Removing both lost the card for a
create on the line after a CRLF continuation.
* fix(editors): launch Open In editors by id from settings
* test(editors): drop settings casts by narrowing the shell store type
* fix(editors): import shell-open types from their moved path
* test(editors): type the shell test settings instead of casting
* fix(web): confirm before a pairing link replaces a saved server
* test(web): drop the stored-environment cast by narrowing the pairing decision input
* i18n(web): translate the replace-saved-server prompt