mirror of
https://github.com/stablyai/orca.git
synced 2026-11-13 17:37:40 +00:00
83ec1c09dd5077a6dff8bb3c94de0d32d0b6ac3b
20689
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
83ec1c09dd |
fix(browser): keep Orca shortcuts working while an HTML document preview has focus (#41066)
* fix(browser): forward Orca shortcuts from focused HTML document previews Workspace-document preview guests never installed the guest shortcut forwarder that browser pages and plugin frames use, so once a preview took focus Ctrl+Tab and the other window shortcuts stopped reaching Orca. Install it in attachWorkspaceDocGuestPolicies, bound to the preview's own host, with browserPage: false so browser-page chords stay with the document, and dispose it with the rest of the doc policy. * test(browser): pin Ctrl+Tab forwarding from a focused HTML document preview * fix(browser): activate a document preview's split when it is clicked A press inside the preview never reaches the host DOM, so forwarded shortcuts such as Close acted on whichever split was active before. * refactor(browser): read a document preview's page id from its guest policy --------- Co-authored-by: agustin2606 <agustinvarela2606@gmail.com> |
||
|
|
e33a851d8e |
fix(claude-accounts): restart sessions after a phone or CLI account switch instead of asking on the desktop (#41064)
A switch made from Orca Mobile or the CLI opened the 'restart running sessions?' dialog on the desktop, where the person switching can't see it. Under the 'Ask' setting these switches now restart the moved sessions the way 'Always restart' does: each waits for its turn to end and resumes its conversation on the new account. |
||
|
|
280bcbc48a | refactor: organize usage and CSV modules by concrete owners (#41059) | ||
|
|
8cac33b751 |
fix(mobile): stop dropping display-mode resizes after a terminal opens (#41061)
The phone's stale-resize filter took the binary scrollback frame's seq as its layout high-water mark, but that seq counts output bytes, not layout changes. A Desktop/Phone toggle on a terminal with little output then looked older than the mark and was dropped, so the phone never resized and kept showing the old mode. Seed the mark from the subscribed frame's layout seq and leave scrollback out of it. Co-authored-by: zhangxaochen <3416677+zhangxaochen@users.noreply.github.com> |
||
|
|
c96271dc5b |
fix(mobile): say Update mobile on desktop chats an old phone app can't show (#41063)
An old mobile app lists a desktop-created structured chat it cannot render with the title 'Update to view', which doesn't say whether the phone or the desktop needs the update. Name the phone app, and document the symptom and recovery steps in the mobile troubleshooting docs. |
||
|
|
fce98d7d21 |
test: remove 167 low-value cases and 93 suites (#41057)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> |
||
|
|
e183ba8bac |
fix(daemon): stop the macOS logout watch adding a login record every two minutes (#41056)
* fix(daemon): stop the macOS logout watch writing a login record every two minutes The watch ran /usr/bin/login as its session-health probe, and each run adds an entry to the macOS login history. Check DNS health first and only run the login probe when the resolver already looks dead, which retirement requires anyway. * fix(daemon): keep probing login after a rejection until PAM accepts again Gate on the last login verdict instead of the rejection streak, so a sleep reset of the streak cannot leave a rejected verdict cached while DNS looks healthy. * test(daemon): keep coverage for not retiring once DNS recovers * test(daemon): drop the duplicate retirement replay from the resolver gate test |
||
|
|
d47ed1c468 |
fix(agent-status): skipping a Codex async question clears it on SSH panes too (#41031)
* fix(agent-status): skipping a Codex async question clears it on SSH panes too An SSH pane's Codex hooks are normalized by orcad on the host, so the desktop's own hook server had no row to apply the skip keystroke to. The renderer now sends a remote pane's skip to the owning runtime through a new terminal.inferCodexQuestionSkip RPC, which applies it to the host's tracker. * test(e2e): skipping a Codex async question clears a managed SSH terminal's row |
||
|
|
7803c9b91c |
fix(source-control): name the base by its short ref in the empty state (#41033)
The Source control empty state named the base by its fully qualified ref ('…no changes ahead of refs/remotes/origin/master'). Show it the way people know it ('origin/master') with a small shortRefLabel helper.
|
||
|
|
b0c431c1a3 | fix(orchestration): archive a released chat worker's journal up to the byte bound, not one 200-row page (#41049) | ||
|
|
3217e60e84 | refactor: give pane conversations a concrete owner and remove redundant wrappers (#41038) | ||
|
|
37ae7de470 |
fix(cursor): list your account's Cursor models in the agent launch picker (#41046)
* fix(cursor): read the default marker in cursor-agent model rows * feat(agent-launch): list a terminal-only agent's own models in the launch picker * fix(agent-launch): cache Cursor listings and keep the seed for fallback lists * fix(agent-launch): keep the host catalog for agents that have structured chats * refactor(agent-launch): resolve the picker's discovery runtime once per render |
||
|
|
d5022c6e46 |
style(new-workspace): icon-only Create From tabs and shorter Create button (#41036)
* style(new-workspace): icon-only Create From tabs and shorter Create button * style(new-workspace): let Tabs primitives own source-tab spacing * chore(i18n): add Create button label to English catalog |
||
|
|
12a6326d1c |
Update README downloads badge (#41050)
Co-authored-by: buf0-bot[bot] <252831055+buf0-bot[bot]@users.noreply.github.com> |
||
|
|
42f55bfa37 |
fix(session-history): index Codex rollouts archived as .jsonl.zst (#40593)
* fix(session-history): index Codex rollouts archived as .jsonl.zst Codex compresses rollouts idle for 7+ days to rollout-*.jsonl.zst. The session scanner only discovered .jsonl files, so every Codex chat older than about a week disappeared from Agent Session History. Discover .zst rollouts, decode them through a shared zstd stream wrapper above openTranscriptReadStream (native, WSL UNC, and SSH alike), never resume a compressed archive from an offset, and drop a .jsonl.zst candidate when its plain .jsonl twin is listed, matching Codex's own rule. * fix(session-history): admit only rollout-named zst archives and close raw zstd streams early Review follow-up on #40593: a filePredicate limits compressed discovery to rollout-*.jsonl.zst so unrelated .zst files are never decompressed, and zstdTranscriptStream links the raw and decoded streams with pipeline so an early close of the decoded stream releases the raw stream's fd. * fix(session-history): cover archived Codex rollouts by compressed size and collapse .zst twins in every listing Archived rollouts keep the bounded resumable reader but never resume, and report their compressed stat size as the read cursor, so search coverage checks match. The .zst suffix is dropped from Codex alias keys with the plain file preferred, which also dedupes scoped walks and rollouts archived in only one home. * fix(session-history): prefer the live rollout over an archive in another Codex home --------- Co-authored-by: Kelvin Amoaba <97001695+AmoabaKelvin@users.noreply.github.com> |
||
|
|
4c8feb5621 |
fix(native-chat): open or reveal folder links, labeled "Open folder", instead of doing nothing (#41040)
* fix(native-chat): open and reveal folder links instead of doing nothing (#40675) * fix(native-chat): reveal folders in their owning worktree and localize the no-route toast (#40675 review) - Activate a folder's owning worktree before revealing it: the explorer only reveals inside the worktree it shows, so a paired host folder in another worktree stayed hidden. - Reject a paired folder outside the worktree root (e.g. a chat scratch folder): the explorer drops those reveals, so report the unavailable route instead of returning silently. - Add an `unavailable` FileOpenFailure verdict with its own localized toast, replacing the English error string that other locales would show. * fix(native-chat): report a folder the OS could not open (#40675 review) `openFilePath` returning false or rejecting left a local folder click with no feedback. The directory route now reports the unavailable path in both cases, with a test covering a refused local folder open. * fix(native-chat): reveal SSH folders in the explorer and report a failed Shift-open of a folder Folders below an SSH workspace root still ended in a 'can't open' toast; the workspace explorer reads through any host, so it shows them. A Shift-open of a local folder that the OS refused returned silently. The trailing-separator hint now also hides the download row. * fix(native-chat): match the owner's host and explorer spelling when revealing a folder A same-ID workspace on another host counted as already selected, a superseded folder click could still toast after a newer one, and an SSH reveal used the chat's separators instead of the explorer's. * fix(file-explorer): reveal a target spelled with other separators, and skip duplicate folder rows and toasts The explorer built a reveal's ancestors in its root's spelling but looked the target up as given, so a forward-slash path under a Windows root selected nothing. A local folder link no longer repeats its open as 'Open with default app', and a blocked folder workspace no longer toasts twice. --------- Co-authored-by: Pr1p <zwq19980411@gmail.com> |
||
|
|
681dab3ff9 |
fix(speech): keep the old speech model when an update can't be moved into place (#41037)
* fix(speech): keep the old model when the new one can't be moved in Deleting the old folder before the rename lost both copies when the rename failed, e.g. a Windows antivirus lock. * fix(speech): keep an interrupted swap's backup and let delete wait for it Retry renames through Windows file locks, and keep .previous when it is the only old copy left. * fix(speech): remove the migration source's model backup on delete * test(speech): assert the kept model, not the backup folder name * refactor(speech): remove each model folder's leftovers in one loop on delete * fix(speech): check model folders with async stat during the swap |
||
|
|
05edb8fd89 |
fix(azure-devops): recognize vs-ssh.visualstudio.com SSH remotes (#40369)
* fix(azure-devops): recognize vs-ssh.visualstudio.com SSH remotes Organizations on the older visualstudio.com URLs clone over SSH with <org>@vs-ssh.visualstudio.com:v3/<org>/<project>/<repo>. The repository parser only accepted ssh.dev.azure.com, so these remotes parsed to null and the repo got no Azure DevOps pull request or status features. Accept vs-ssh.visualstudio.com in both the SCP and ssh:// forms, and resolve it to the same reference the org's https://<org>.visualstudio.com remote already gets. Fixes #ISSUE * fix(azure-devops): validate vs-ssh org names and fix renderer PR links A vs-ssh remote's org becomes the API hostname that receives the Azure DevOps PAT, so reject anything but a plain org name. The renderer's manual PR link parser also missed vs-ssh remotes and built a link on vs-ssh.visualstudio.com; resolve it to the org's visualstudio.com repo. --------- Co-authored-by: Kelvin Amoaba <97001695+AmoabaKelvin@users.noreply.github.com> |
||
|
|
5e342d7e1a |
fix(orchestration): a worker report during an Orca restart is not rejected as a changed identity (#41014)
* fix(orchestration): a worker report during an Orca restart is not rejected as a changed identity * refactor(orchestration): share the startup bounded wait; skip long-poll checks * chore(orchestration): drop casts in the restart identity wait * fix(orchestration): only long-poll checks skip the restart identity wait * fix(orchestration): ordinary mail never waits for the restart identity restore |
||
|
|
d3ef8b4255 |
test: remove 216 low-value cases and 42 whole suites (#41030)
* test: remove 216 low-value cases and 42 whole suites * test: retire unprotected snapshot adoption gate --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> |
||
|
|
ba3f9918f1 |
relay-edge: reconnect_gap metric (time from a host's last control close to its next activation) (#41034)
Diagnostics only. Separates sleeping hosts (long gap) from awake hosts whose connection was dropped (short gap) after silence closes. Stores one small per-host key, cleared on the next activation and by erase. |
||
|
|
ada663ef62 |
fix(bitbucket): connect access tokens and API tokens without account access (#41029)
* fix(bitbucket): connect access tokens and API tokens without account access Bitbucket answers GET /2.0/user with 403 for a credential it accepts but that has no account access: every repository, project or workspace access token, and API tokens without read:user:bitbucket. Orca treated that 403 as a rejected credential, so those tokens could never connect. Only 401 now means rejected; 403 connects without an account name. * test(bitbucket): type the 403 fetch stub without a cast * fix(bitbucket): accept a /user 403 only when Bitbucket sent it |
||
|
|
80026db12a | refactor(renderer): place remaining library features with their owners (#41024) | ||
|
|
d30ea72469 |
fix(session-history): discover OMP profile session dirs (#40264)
* fix(session-history): discover OMP profile session dirs OMP stores per-profile transcripts under <config home>/profiles/<name>/agent/sessions (XDG_DATA_HOME/omp/profiles/<name>/sessions on POSIX with XDG set). The app process usually lacks OMP_PROFILE/PI_PROFILE, so profile-run sessions were missing from Agent Session History, orca search, and native chat. Enumerate existing profile session dirs in ompProfileSessionsDirs() (same env + safety rules as resolveOmpSessionsDir; PI_CONFIG_DIR-aware; suppressed under the legacy OMP_CODING_AGENT_DIR override) and include them in ompSessionsRootDirs() (discovery + path allowlist) and the omp branch of the native chat resolver. An explicit ompSessionsDir override still pins one location. main-sync-fs baseline for omp-session-root.ts 1 -> 3: one readdir of the small fixed profiles dir plus one existsSync candidate check per profile (single call site), the same small-dir probe style the file already uses - not a per-file sweep. Flagged for reviewer sign-off per the ratchet's rule. * fix(session-history): enumerate XDG-only OMP profile dirs ompProfileSessionsDirs only listed profile names from the local config home, so a profile that exists solely under $XDG_DATA_HOME/omp/profiles (e.g. OMP run with a different PI_CONFIG_DIR) was never discovered. Enumerate both roots; per-profile candidate checks and output dedup are unchanged. * docs(session-history): document profile dir helpers for coverage * fix(session-history): use non-blocking profile enumeration in the native chat ID lookup * refactor(session-history): share one OMP root list for discovery and chat lookup Drop the duplicated async profile scan: native chat ID lookup now reuses ompSessionsRootDirs, which already runs the small sync profile probe on the main process for row deletion. Reuse normalizedProfile for directory names and trim tests to the behavior that fails on revert. * fix(session-history): prefer a profile's XDG sessions dir in OMP ID lookup --------- Co-authored-by: ducts <ducts@fpt.com> Co-authored-by: Kelvin Amoaba <97001695+AmoabaKelvin@users.noreply.github.com> |
||
|
|
b7e0fa8e22 |
feat(automations): redesign the automation detail overview (#40507)
* feat(automations): redesign the automation detail overview Group the overview into a run-health band (last run, next run, spend), Schedule and Execution property panels, and a Prompt panel with copy and a fading show-more. Run Now is now the primary action next to Edit; Pause and Delete move into an overflow menu with Delete separated as destructive. * test(e2e): align prompt disclosure spec with the 8-line clamp The redesign raised the collapsed prompt clamp from 4 to 8 lines and caps the prompt at 80ch, so the resize prompt no longer overflowed at 820px. Lengthen it so it wraps to ~11 lines at 820px and ~6 at 1400px, and assert line-clamp 8. Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
5401c07619 |
test: remove 436 low-value cases and 79 whole suites (#41026)
* test: remove 436 low-value cases across 79 whole suites * test: prune obsolete popup and stdin timing allowances --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> |
||
|
|
c26e259d0f |
fix(native-chat): show session skill argument hints in the picker (#40788)
* fix(native-chat): show session skill argument hints in the picker Claude Code reports argument-hint on skill commands. The native chat skill row kept only the name and description, while built-in commands in the same picker still showed their hint. * fix(native-chat): keep a skill's hint before Claude classifies its catalog Before the first stream init, Claude lists skills as unclassified commands. A scanned skill of the same name replaces that row and dropped its hint. Fold the three hint tests into one shared-layer test and show a skill hint in the picker fixture. --------- Co-authored-by: Kelvin Amoaba <97001695+AmoabaKelvin@users.noreply.github.com> |
||
|
+26 |
2a98a4365f |
style(menus): roomier rows, lighter icons, solid surface (#40000)
* style(menus): roomier 26px rows, lighter icons, solid surface Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(orchestration): record orchestration as the origin of nested workers on connected servers; lead the guide with new-child (#40091) worker-start --on <server> --worktree new-child now tells the server that orchestration picked the parent, so the server records the child's lineage as orchestration, as a local child is, instead of cli. Older coordinators omit the field and keep cli. The guide now shows new-child first and new-top-level as the no-parent choice. * fix(claude): name Orca as the client of its Claude chats (#40057) * fix(claude): name Orca as the client of its Claude chats Orca's Claude chats reported the SDK's default entrypoint (sdk-ts), or the value of a Claude session Orca was launched from. Set CLAUDE_CODE_ENTRYPOINT to orca for every structured Claude launch; a value in Orca's launch environment still wins. * fix(claude): keep a differently cased Windows entrypoint override Windows env names are case-insensitive, so a launch value spelled claude_code_entrypoint lost to the uppercase Orca default when Node deduplicated the keys. * fix(claude): let a launch value replace a differently cased inherited one on Windows * fix(claude): store a Windows entrypoint override under the name the SDK reads * fix(orchestration): refuse a paired-server worker start onto a busy terminal before any wait (#40102) One terminal claim owner now covers local Dispatches and attachments a paired coordinator starts here, so either kind refuses the other with terminal_busy before readiness waits or briefs. * Show usage reset dates in account switcher (#40210) * feat(cli): add `orca vm env doctor` to check that an environment can run agents (#40120) * feat(cli): add orca vm env doctor to check a workspace environment Checks required CLIs (git plus what the repo manifests imply), agent CLIs and their sign-in, Git fetch and a dry-run push, the orca.yaml setup script (optionally re-running it with Orca's runner), and free disk. Pass/warn/fail with --json; checks live in src/main/environment-doctor for runtime reuse. * fix(env-doctor): ship the doctor modules in the packaged CLI and share the check formatter * fix(env-doctor): run Git probes in the C locale so folder detection is locale-independent * fix(orchestration): keep a paired server's worker list when one Dispatch is from an earlier pairing (#40170) * fix(orchestration): keep a paired server's worker list when one Dispatch is from an earlier pairing The server's fleet snapshot refused the whole batch when one requested Dispatch was not this home's (for example, one started before the home re-paired), so the home showed every worker on that server as host_unavailable. Now only that Dispatch reads as unverifiable. * test(orchestration): cover a live Dispatch held for another home in the fleet snapshot * test(orchestration): assert the other home's fleet item without a cast * fix(ci): reuse installed pinned Bun in test workflows (#40234) * fix(vm): resume a paired-server VM whose host went away on its own (#40199) * fix(vm): resume a paired-server VM whose host went away on its own * fix(vm): count only continuous failures as a lost paired server * fix(browser): restrict paired-host browser tunnel destinations (#40203) * feat(mobile): cancel dictation in place and show which device is transcribing (#40185) * feat(mobile): cancel dictation in place and show which device is transcribing * fix(mobile): give each composer its own dictation cancel target * fix(mobile): keep the dictating composer row on one line * refactor(mobile): share the dictation mic face and measure the cancel target per platform * fix: request native ABI process report only on Linux (#40233) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * feat(vm-recipes): add "Set up with an agent" to Cloud VMs settings (#40131) * feat(vm-recipes): add Set up with an agent to the Cloud VMs settings Starts the default agent in the project's workspace with a prompt that loads the per-workspace environment skill, loops on the recipe and environment doctors, and ends with a commit and PR. The launcher also takes failure context (redacted log tail) for callers such as a failed VM create. * refactor: split recipe log redaction into a browser-safe module * fix(vm-recipes): bound and redact failure text in the setup-agent prompt * fix(worktrees): offer nested-worktree delete on remote runtime hosts (#40235) * fix(worktrees): offer nested-worktree delete for remote runtime hosts A remote host's 'contains another registered worktree' refusal showed only the raw error. Add worktree.previewNestedRemoval and an approved-plan worktree.rm path on the runtime, and route the toast's nested-delete dialog to the workspace's own host. * fix(worktrees): re-check checkouts between remote nested deletes; scale reply timeout * chore: compose nested worktree ids; record improved ratchets --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * fix(speech): send cloud dictation through the proxy set in Settings (#40236) * fix(speech): send cloud dictation through the proxy set in Settings * fix(speech): keep OpenAI cookies out of the desktop session * refactor(speech): send transcription and the key check through one request helper * refactor: move browser contracts and publication to defining owners (#40209) * refactor: move atomic publication to its filesystem owner * refactor: group shared browser definitions by feature * refactor: bind proxy process and session contracts to defining owners * refactor: consolidate direct session contract type imports * refactor: retain atomic publication test timing under moved owner * fix(benchmark): resolve historical tunnel framing source before loading * Plugins: add workspace.rename and project names in workspace.list (#40197) * feat(plugins): add workspace.rename and project names in workspace.list Plugins that name workspaces had to read Orca's private runtime token and call worktree.set over the runtime socket, bypassing capability consent. workspace.rename (workspace:write, worker only, host API 1.5) does the same update as a sidebar rename. workspace.list rows gain the project name so plugins can prefix names without reading the runtime's repo list. * fix(plugins): harden workspace.rename against twin folders and hidden characters Folder renames require a unique folder id, so twins on two hosts are not both renamed, and fail when no folder has the id. Names refuse C1, bidi and zero-width characters, which could make a label read as another workspace's name. * fix(plugins): workspace.rename matches a sidebar rename for folders and reports kept names A folder rename also cancels a pending first-agent-message rename, so the automatic title cannot replace the plugin's name. A rename Orca does not apply (during a WSL move) is a conflict instead of a silent success. workspace.list's project is optional, so mocks written for host API 1.4 still validate. More invisible characters are refused. * feat(dictation): dictate into the focused field of a page in the browser pane (#40191) * feat(dictation): dictate into the focused field of a page in the browser pane * test(dictation): cover dictation into a focused browser page * fix(dictation): type page dictation through the frame that owns the field * fix(dictation): space page rich-text dictation within its block and offer editors the beforeinput * test(dictation): simplify the page insertion test mock * fix(dictation): copy page dictation to the clipboard when an editor blocks the input * feat(dictation): Enter or Send while dictating sends once the words land (#40226) * feat(dictation): Enter or Send while dictating sends once the words land * refactor(dictation): composer queued send as a hook * fix(dictation): queue only Enter typed into the terminal; keep the pill until the send runs * fix(dictation): a cancel during the terminal's Enter delay drops the Enter * fix(dictation): keep the queued label until the terminal Enter is pressed * fix(dictation): keep the queued send compilable * feat(vm-recipes): build checklist and failure card for VM creates (#40152) After a recipe provisions a VM, run the environment doctor on the VM's own server (new environment.doctor RPC) before creating the workspace. The VM create sheet shows Provision VM, Check environment and Create workspace; a failed step gets Fix with agent, Retry, Edit recipe, and (for checks) Open anyway, which keeps the VM. Older VM servers skip the checks; dismissing aborts a running check and destroys the VM as before. * Polish agent picker search and rows (#40242) * wip * Polish agent picker interactions * test: reconcile VM mobile and native test removals with current main (#40154) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * test: remove low-value shared and native suites (#40172) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * Fix Simplified Chinese translation for floating button action (#40252) * fix(vm-recipes): destroy a recipe VM when a phone deletes its workspace (#40205) Deleting a recipe workspace from the phone removed only its checkout and left the VM this desktop created for it running. Only the desktop window ran the destroy. The relaying desktop now tags the rows of workspaces whose VMs it created with the environment's name, and says whether deleting will destroy it. The phone's delete sheet names the environment, and its delete asks for the destroy (`destroyHost: true`). The desktop then owns that removal: - it runs as a workspace lifecycle delete - the environment's Orca removes the checkout and must answer positively. An older Orca that answers on acceptance is polled until the workspace is gone. - the VM is destroyed through the shared cleanup, behind any running wake or suspend, and only when no other workspace remains on it - the result reports host.state truthfully: destroyed, kept, or left-running (no destroy step) The environment's own error codes reach the phone unchanged, and a failed removal shows its message on the phone instead of only a haptic. Removals that don't ask for the destroy (older phones, the CLI, other clients) keep today's behavior. No CLI API changes. Based on #39235 by jutaz, a port of #28435. Co-authored-by: Justas Brazauskas <brazauskasjustas@gmail.com> * fix(dictation): stop phone and browser cloud dictation at the 10-minute limit with a notice (#40240) * fix(dictation): stop a phone's cloud dictation at the 10-minute limit with a notice * test(dictation): pin the cap flag on every phone chunk reply * perf(dictation): skip decoding phone audio the host will drop past the cloud cap * ci(release): mirror published downloads to Cloudflare R2 (#40254) onorca.dev offers an opt-in 'mirror link' (https://downloads.onorca.dev) next to the GitHub download for when GitHub release downloads 5xx. Upload the onorca.dev download assets there right after each stable desktop release and each Android release, instead of polling. - config/scripts/release/publication/mirror-release-to-r2.sh: retrying, resumable download from GitHub, size + sha256 check, S3 multipart upload to R2 (no 300 MiB wrangler cap) - release-mirror-r2.yml: reusable + manual backfill - release-cut: run after publish-release for stable vX.Y.Z tags only - mobile-android-release: run before bump-apk-download so the site's mirror link never points at a missing APK (success not required) * Keep hosted reviews, conversations, and optional GitLab jobs accurate (#40080) * Fix hosted review selection, conversations and optional job failures Co-authored-by: Mahedi Hasan Emon <mahedi.emon62@gmail.com> Co-authored-by: Victor GALISSON <victor.galisson@purecontrol.com> * Retain complete review history within provider bounds * Declare optional membership retention policy * Narrow hydrated revision metadata without a cast * Preserve completed check presentation through the shared classifier * Read malformed revision metadata without retaining it * Exercise legacy alternate discovery after local absence * Preserve observable remote review routing coverage * Keep optional GitLab job warnings consistent in details * Reuse the optional job presentation color --------- Co-authored-by: Victor GALISSON <victor.galisson@purecontrol.com> * Continue every usage-limited chat at once, and stop after five automatic refails (#40055) * fix(native-chat): continue every usage-limited chat at once and stop after five automatic refails The automatic continue sent one chat per 10 s sweep, so chats stopped by the same limit resumed one by one. Its retry budget belonged to the cut, so a continuation that hit the limit again started a fresh budget and could repeat indefinitely. Send every due chat in one pass, one at a time. Count consecutive automatic continues that ended in another usage limit from the journal: each continue's message id names the cut it answered, and the next cut's turn is joined to that submission through its key or provider item. After five, the chat shows that Orca won't continue it automatically. * fix(native-chat): read the usage-limit continue chain from the tail, not the whole conversation The chain walk built a map over every journal row and rescanned history for each link. Walk back from the end instead, so the work is the chain's own rows; add an N/10N contract. Replace the fan-out test's casts with typed fixtures. * test(native-chat): count a Claude echo-opened continue in the usage-limit chain * fix(native-chat): derive the usage-limit continue chain once per cut A status rebuild for the same cut reuses the chain it already derived, since only history before the cut decides it; the turn's limit is read without copying its rows. * fix(native-chat): skip slash-command turns when walking a usage-limit continue chain A /compact run after a usage limit sits between the cut and its automatic continue; the latest-turn read skips it, so the chain walk must too. Count visited rows in the perf contracts with typed getters. * test(native-chat): type-guard the recorded Claude capture events * fix(native-chat): recompute the usage-limit chain when a late receipt attributes its opener Reuse across rebuilds is keyed on the cut, its turn row's revision and the newest send, so a late attribution that completes a join is counted instead of keeping a stale zero. * test(native-chat): guard usage-limit chain reuse at the status projection Drives StructuredAgentSessionJournalProjections.read through real journal invalidations at 100 and 1000 turn rows: one chain derivation for an unchanged cut, again for a new cut or epoch, and a recount when a late receipt attributes the continue's opener. * fix(native-chat): reuse a usage-limit chain only while everything it read is unchanged The chain walk now reports the turn rows it looked up and the oldest submission it examined; the status projection keys reuse on their revisions and join evidence, so a late receipt for any link, not just the newest send, recounts the chain. * fix(native-chat): derive the usage-limit chain fresh on each status rebuild Reuse across rebuilds kept missing inputs the walk reads (late receipts, revised failure rows) and its key re-serialized settled history. The status projection's own cache still skips unchanged reads; each rebuild now walks only the chain's tail. Contract tests at the projection count total reads: independent of earlier history, linear in the chain's rows, one scan of the sends when no opener matches. * fix(native-chat): find an echo-opened turn's opener without reading the turn before it A Claude echo-opened turn names the provider's key while its opener row keeps the submission's, so the slash-command check scanned the whole previous turn and missed echo-opened commands. It now stops at the nearest root user row. * fix(dictation): save Auto mode so older builds keep a working shortcut, and show it on the phone (#40231) * fix(dictation): store Auto as Toggle plus hold-to-record so older builds keep a working shortcut * test(mobile): type the Auto mode settings fake instead of casting * fix(dictation): migrate a stored Hold without hold-to-record * fix(dictation): keep phone mode segments typed and clear hold-to-record when a phone picks Hold * refactor(dictation): reuse the shared mode settings in the migration and phone writes * fix(agent-picker): list agents named by the search before other agents' model setups (#39806) * fix(agent-picker): list agents named by the search before other agents' model setups Typing "codex" in the agent picker showed OpenCode/Cursor model setups (e.g. "OpenCode · GPT-5 Codex") above the Codex agent itself, and Enter picked the first setup. Direct agent matches now render first and are the Enter target. * test(agent-picker): assert search highlight and Enter target for named agent * test(agent-picker): import fireEvent after rebase * test: remove low-value WSL and renderer suites (#40237) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * fix(native-chat): pad the sender name chip in orchestration worker cards (#40258) The compact sender name had no horizontal padding, so its hover fill hugged the text. Add an inlineChip button size (inline height, px-1.5). * test: remove low-value renderer and budget suites (#40222) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * docs: put Chat or Terminal first in README features (#40262) * fix(dictation): a paired phone or browser waits as long as the computer for long cloud dictations (#40238) * fix(dictation): wait as long as the host's cloud deadline when a paired phone or browser stops * fix(dictation): compute the host's cloud deadline from its exact sample count * fix(orchestration): explain the --terminal and --agent refusal; name chat addresses in terminal commands (#40092) * docs(dictation): say why Hold can't see a key release inside a browser page (#40269) * test: remove low-value mobile renderer and rate-limit suites (#40188) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * fix(terminal): end a dead preserved terminal host's PTYs as host loss (#40095) * fix(terminal): end a dead preserved terminal host's PTYs as host loss After an update Orca keeps the previous version's terminal host so agents survive. That host has no respawn, so when it later died nothing ended its PTYs: panes stayed connected on a frozen frame and input went nowhere. Once every reconnect attempt finds its endpoint refused or missing, each of its PTYs now ends as host loss with history kept, and the pane's restore is no longer refused because the dead host cannot answer. Fixes #38432 * fix(terminal): require process-exit proof on POSIX and keep checking until proven Review follow-ups: an unproven attempt restarts the count instead of ending the check; on POSIX the old host's pid must also be gone; a proven-gone host answers 'not live' for every id; one throwing exit listener cannot strand the remaining sessions. * feat(i18n): translate the dictation pill, error pill and queued-send copy (#40266) * fix(dictation): don't throw when the paired web client has no speech catalog * feat(i18n): translate the dictation pill, error pill and queued-send copy * fix(i18n): say Chinese queued sends happen automatically * test: remove low-value provider and renderer assertions (#40279) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * test: remove low-value copy, inventory, and runner assertions (#40282) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * feat(release): publish a server-only Linux tarball for orca serve (#40280) * feat(release): publish a server-only Linux tarball for orca serve Each release now also uploads orca-server-linux-x64.tar.gz and orca-server-linux-arm64.tar.gz (orcad slot from the qualified template, the pinned Node, and an orca-ide launcher) plus orca-server-sha256sums.txt, so a Linux host can run orca serve without the desktop package. The tarballs are packed and smoke-tested (serve --recipe-json, then pair a second profile) on both architectures, including bare ubuntu:24.04 and debian:12-slim containers. Upload runs only after the release is published and nothing depends on it, so it cannot hold the desktop release. * fix(release): keep the server tarball's launcher env out of its terminals; skip refs that predate it - The launcher runs the CLI with ELECTRON_RUN_AS_NODE=1, as the packaged app does, and the CLI strips it before starting orcad; ORCA_APP_EXECUTABLE and ORCA_SERVE_RUNTIME are cleared. - Ship Node's LICENSE beside the runtime. - Skip packing on release refs that predate the scripts, and upload only when both tarballs passed. - Run the PR smoke when the CLI's serve-runtime selection changes; document service install. * refactor: group renderer workspace ownership and navigation (#40230) * refactor: group renderer workspace ownership and navigation * refactor: use the defining WSL rewrite store identifier * refactor: route new upstream consumers to workspace owners * refactor: consolidate connection owner test imports * refactor: preserve upstream review-owner test retirement * test: remove low-value wrappers, inventories, and timing checks (#40284) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * test(vm): pin file saves in a recipe-created workspace, across server restart (#11762) (#40275) * test(vm): pin file saves in a recipe-created Orca server workspace (#11762) * test(vm): wait for the save round trip, let the app reconnect itself, edit a plain-text file * test(vm): say why the recipe save spec needs a longer timeout * fix(tabs): preserve lastFocusedAt on native chat tabs across host snapshots (#40288) Host session-tab snapshots rebuild native chat tabs without the client-owned focus visit, so Cmd+J recents ranked chats last and showed their creation time. Fixes #39841 * test: remove low-value renderer, chain, and native checks (#40287) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * test: remove low-value work budgets and relocation selftest (#40294) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * fix(ports): keep sticky External Ports header opaque on hover (#40073) The sticky External Ports header used hover:bg-accent/50, a translucent background that let scrolled port rows show through on hover. Blend the accent into the popover color so the hover state stays opaque. Fixes #40056 * fix(tour): allow chat split for agent sessions without a TUI agent tag (#39976) The native chat split action required the source agent-session tab to carry a TUI agent tag, so sessions without one (e.g. untagged or non-TUI agents) could not be split and the tour's split step stalled. Any agent-session tab in a known group is now a valid split source. Co-authored-by: Neil <neil@stably.ai> * fix(native-chat): move the cursor to the composer after Add to chat (#39845) The composer refuses focus while an overlay is open, and the selection popover was still open when the quote was appended. Close it first. * test(pty): await readiness signals instead of polling with waitFor (#40082) The plain-shell readiness test polled with vi.waitFor (1s default budget) for reconcileConfig and the spawn env. Under CPU load the spawn takes over a second and the test failed with 'expected undefined to be defined'. Await an explicit reconcile-started signal and the spawn itself, and move cleanup to onTestFinished so the gate is released and spies/env restored even when a regressed spawn blocks until the test timeout. Fixes #40078 Co-authored-by: Jerry Wu <haoyuwu@andrew.cmu.edu> * fix(terminal): don't restart every dead saved tab when a worktree opens; log how the daemon exited (#40289) * fix(terminal): don't restart every dead saved tab when a worktree opens; log how the daemon exited Opening a worktree mounted every saved terminal tab that had no PTY, and each hidden mount started a fresh shell or agent. With many finished agent tabs this started dozens of agents at once and could exhaust a host's process limit. Saved tabs with no PTY anywhere and nothing queued to start now wait until they are shown; the existing capped idle warm-up still admits up to four. The main process now records the daemon's exit code or signal and names it in the respawn log line. Fixes #39166 * fix(daemon): forget a predecessor's exit when a replacement daemon launches * fix(diff): persist inline / side-by-side diff view via the Default Diff View setting (#40256) * fix(diff): persist inline / side-by-side diff view via the Default Diff View setting The file diff and combined diff toolbars toggled inline vs side-by-side only in local component state (plus a session-only module preference for the combined diff), so switching worktrees or agent threads reopened the diff in the saved inline default. The toggle now writes the existing diffDefaultView setting, and both viewers derive sideBySide directly from it. The per-view cache and module memory no longer carry a separate sideBySide value. Fixes #40241 Co-authored-by: Wooseong Kim <2222333+innocarpe@users.noreply.github.com> * test(diff): drop the removed sideBySide field from the cached combined-diff view --------- Co-authored-by: Neil <neil@stably.ai> * feat(dashboard): show last messages in agent dialog when no live terminal (#40147) When a dashboard card has no live PTY (e.g. chat-session tabs), the agent dialog previously showed only the "preview unavailable" notice. It now also renders the card's stored last user/agent messages, unclamped and scrollable, below the notice. The rendering is extracted into AgentCardLastMessages and shared with the kanban card, which keeps its line clamps. Fixes #40144 Co-authored-by: Neil <neil@stably.ai> * fix(claude): verify model switches when terminal echoes omit vendor prefix (#40064) Claude echoes "Set model to Opus 5.5" without the "Claude" vendor prefix, and never echoes the picker-only " alias" suffix or a raw "claude-" id prefix. The confirmation observer required every picker-label token, so a successful switch resolved to unknown and showed "Could not verify the model change". Normalize the expected label before matching; context tokens such as 1M are still required. Fixes #40058 Co-authored-by: Neil <neil@stably.ai> * fix(markdown): lower link underlines below descenders (#40218) Link underlines in Native Chat, the markdown preview and the rich markdown editor sat 2px below the baseline, so descenders (g, y, p, j) crossed them and skip-ink broke the line into dashes. Use a 0.25em offset that scales with font size and zoom, and override the shared renderer's underline-offset-2 in Native Chat. Fixes #40217 Co-authored-by: Neil <neil@stably.ai> * test: remove low-value copy suites and manual status benchmark (#40305) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * fix(native-chat): group deferred context rows separately in the usage popover (#39917) Claude reports deferred categories (MCP tools, system tools loaded on demand) that sit outside the used total, but summarizeContextUsage dropped the flag, so the popover listed them as window percentages next to real usage and the rows summed to well over 100%. Keep the deferred flag on each summary row and render deferred rows in their own group under a divider, with token counts instead of a share of the window and a note that they are not counted in the used total. Fixes #39878 Co-authored-by: Neil <neil@stably.ai> * refactor: group editor browser document and simulator owners (#40273) * refactor: group editor browser document and simulator owners * refactor: update active simulator reliability command links * refactor: preserve upstream editor and emulator test retirements * fix(codex): close TOML multiline strings on runs of four or five quotes (#40089) The Codex config line scanner only treated exactly three quotes as the multiline closer, so a value like '''printf 'ok'''' left the scanner inside the string and later tables (e.g. [projects."..."]) were missed when writing project trust. Match toml_parser: a run of 3-5 quotes closes the string, with up to two quotes belonging to the content. Co-authored-by: Neil <neil@stably.ai> * fix(linear): include project in Linear issue list and search results (#40194) Request the project on the shared issue node fields and map it in mapRawIssueForWorkspace, so list/search rows carry the project the same way issue detail already did. Detail now reuses the shared mapping. Co-authored-by: Neil <neil@stably.ai> * fix(build): bundle browser-extension-preload as a standalone sandboxed script (#39884) The browser-extension preload was a main-build Rollup input, so it could be split into shared CJS chunks that a sandboxed preload cannot require. Build it with the other guest preloads as a self-contained bundle, and share the one-byte unminified output options between the preload build and sandboxed bundles so the extension preload stays one-byte in V8. Co-authored-by: Neil <neil@stably.ai> * test: remove obsolete manual tools and duplicate launch coverage (#40317) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * fix(terminal): ignore the inverse caret glyph in an empty Claude composer (#40225) Claude paints the caret over the first glyph of a dim composer suggestion as an undimmed inverse cell. The typed-text read kept that glyph, so an empty composer reported a one-character draft and the stock Try "..." placeholder was never recognized. Treat a lone inverse caret glyph ahead of a longer dim suggestion as untyped, while keeping a real typed last glyph that sits before a dim argument hint (e.g. /commit [message]). Fixes #40195 Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com> * test(e2e): give the provisioned-root VM a reachable git remote (#40318) * test(e2e): give the provisioned-root VM a reachable git remote VM creates now run the environment checks before creating the workspace (#40152). The fixture VM's origin pointed at a GitHub URL it cannot push to, so the git push check failed and the create paused on the build sheet; the spec then read the VM's primary checkout before it was adopted. Point the VM checkout at a local bare repo so the checks pass. * test(e2e): wait for the provisioned root's adoption, not its listing The VM's primary checkout appears under its branch name once its project is set up, before the environment checks finish and adoption writes ephemeralVmCheckoutMode. Poll for the adopted row instead. * refactor(environment-providers): add EnvironmentProviderDriver, contract test kit and ShellRecipeDriver (#40315) One lifecycle seam (create/resume/suspend/destroy/status + capability flags and a catalogued error type) that every environment provider implements, a shared vitest contract any driver runs from its own test, and ShellRecipeDriver, which wraps today's orca.yaml / plugin VM recipe runner and passes the contract. No production callers yet. * refactor: group agent launch, status, and messaging owners (#40313) * refactor: group agent launch, status, and messaging owners * refactor: consolidate direct owner imports * refactor: import pane ownership directly in status listeners * Update README downloads badge (#40336) Co-authored-by: buf0-bot[bot] <252831055+buf0-bot[bot]@users.noreply.github.com> * refactor(environment-providers): run shell recipes through ShellRecipeDriver (#40332) The runtime service and failed-start cleanup now reach orca.yaml environment recipes and plugin VM recipes through ShellRecipeDriver's recipe-shaped steps. Same arguments, same runner, same results: records, failure copy and diagnostics are unchanged. * test: remove low-value hook and mirror tests and search benchmarks (#40335) * test: remove private hook checks and manual search benchmarks * test: remove masked mirror hydration case and exclusive scaffolding --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * fix(native-chat): show approved Codex automatic reviews as neutral notices (#40161) Codex reports both approved and denied automatic approval reviews on the guardianWarning channel. Orca rendered every one as a yellow "safety review warning", so routine approvals looked like problems. Approved reviews now render as a neutral "approved this action" notice on desktop and mobile; denials and timeouts keep the warning tone. Co-authored-by: Sean876-alt <224890246+Sean876-alt@users.noreply.github.com> Co-authored-by: Neil <neil@stably.ai> * test: remove low-value composer activation provider and layout coverage (#40342) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * test: remove low-value draft and editor save coverage (#40350) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * test: remove low-value bridge speech and lineage checks (#40356) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * fix(vm-recipes): keep a VM's checkout out of the sidebar until its create finishes (#40355) A recipe VM create registers the VM's project before its environment checks run, so the VM's primary checkout showed as a normal workspace next to the pending row while the checks ran or were paused on a failure. Hide that checkout in both sidebar list models until the create adopts it (or makes its worktree). A cancelled or failed create keeps it hidden while its VM is cleaned up; a VM that could not be cleaned up is shown again so it can be removed. * test: remove low-value messaging simulator and editor suites (#40363) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * feat(runtime): tell phones when relay hosts change (#40122) * feat(runtime): tell phones when relay hosts change * fix(runtime): keep the relay host backstop live and watch every list input * fix(mobile): hold the relay host feed only for desktops that announce changes * perf(runtime): watch relay host inputs only while phones read the list * perf(github): use the desktop's PR fallback rule on the phone and forward refreshes (#40128) * perf(github): use the desktop's PR fallback rule on the phone and forward refreshes * fix(github): keep a merged fallback PR while the phone has no head * feat(mobile): keep Tasks and new-workspace drafts across kills (#40127) * feat(mobile): keep Tasks and new-workspace drafts across kills Task comments (per item and project row), the New issue title and body, and the New workspace note now live in device-store draft rows. They come back after the form closes or the app is killed, and only into an empty field. A comment's setter stays bound to its item, so a send that settles after the user moved on clears the right row. * fix(mobile): rebuild comment sends when the draft's item changes * fix(mobile): key the workspace note by host and keep cleared fields cleared * fix(mobile): clear only the note a finished create sent * fix(mobile): count clearing an empty draft field as the user's choice * perf(mobile): cap field drafts, read sheet drafts on open, retry a failed read once * fix(mobile): retry a failed draft read after a pause and keep New issue text typed during a create * fix(mobile): save draft text again once a failed store read can be retried * fix(mobile): remove a stored draft when an unread field is cleared * fix(mobile): floor event-driven reads after failures and catch up reads that span a stream reopen (#40142) * fix(mobile): floor event-driven reads after failures and catch up reads that span a stream reopen * test(mobile): pin the event router's read floor after a refused read in a recording * perf(mobile): stop rebooting the Home spare page on every hop and after iOS memory warnings (#40270) * perf(mobile): back off spare page refills after an unclaimed drop or memory warning * fix(mobile): skip a spare whose store read outlived an unclaimed drop * fix(mobile): arm the spare refill timer on whole milliseconds * feat(vm-recipes): show VM lifecycle states in the sidebar, with Suspend/Resume VM (#40046) * feat(vm-recipes): show VM lifecycle states in the sidebar, with Suspend/Resume VM * fix(vm-recipes): Suspend VM suspends an idle parent with active children; dedupe repeat suspends - With active children, Suspend VM sleeps this workspace too, so its VM suspends once their sessions stop. - A repeat Suspend VM while one is pending is dropped in the coordinator instead of trusting a possibly stale suspended record. - After a direct suspend, re-probe the host so its header reads Suspended. * perf(mobile): keep three visited terminals mounted (#40111) * perf(mobile): keep three visited terminals mounted and release hidden WebGL * fix(mobile): scope the mounted-terminal LRU to the terminal frame * fix(mobile): keep chat's lease-only stream when a terminal pane unmounts * fix(mobile): report a hidden terminal's cell box only once it is shown * perf(mobile): keep hidden terminals' WebGL contexts instead of rebuilding them on every switch * feat(mobile): open chats on their last messages after a relaunch (#40166) * feat(mobile): open chats on their last messages after a relaunch The phone's store keeps each chat's newest rows (up to 512 KiB, 500 rows) and its resume point, written when a turn settles, on hidden and when the chat closes. A relaunched session opens on its stored chat tab, paints the saved rows, and resumes from the stored cursor; the live read restates what the agent is doing. Offline, the composer line says when the copy is from. * test(mobile): keep the relaunch test typechecking * i18n(mobile): translate the offline as-of line * perf(mobile): encode chat copies in slices off the settle frame * feat(mobile): keep commit, PR and review drafts across app kills (#40114) * feat(mobile): keep commit, PR and review drafts across kills * refactor(mobile): build commit, PR and review drafts on the shared draft fields, and clear only the text that was sent * fix(mobile): keep a toggle made during Write with AI, the edit note while its sheet closes, and a newer PR edit after an earlier save * test(mobile): wait for the saved review note row instead of sleeping * perf(mobile): keep a hash of the PR text an edit was typed against, not a second copy * test: remove low-value VM creation assertions (#40367) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * perf(mobile): open Home with last-known workspaces and counts (#40129) * perf(mobile): open Home with last-known workspaces and counts * fix(mobile): keep disconnected desktops on Home and judge agents by the client's connect time * fix(mobile): store the seeded Home counts before removing the old snapshot * fix(mobile): floor router reads after failures, catch up reads that span a stream reopen, seed the wide host list from Home * fix(mobile): keep the old Home snapshot until the store can take it, and never re-date stored totals * perf(mobile): key Home's counts in the host list module so the page boot never loads Home's code * test(mobile): type the Home catalog adapter's modules with type imports * perf(mobile): read Home's stored rows in one batch beside the host list, and keep mark-read a delta read * perf(mobile): paint Home's desktop rows without waiting for the stored counts * perf(mobile): restore Home's stored rows after the desktop list paints, from its host ids * perf(mobile): read Home's counts on the connected edge itself, not a render later * test: remove browser startup and CLI prerequisite mock suites (#40371) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * test: remove low-value VM, mobile, work-item and terminal suites (#40376) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * test: remove sidebar VM-wake and template hover suites (#40379) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * fix(vm-recipes): hide an in-progress VM checkout in every window, the phone and the jump palette (#40373) * fix(vm-recipes): hide an in-progress VM checkout in every window, the phone and the jump palette A VM create's checkout was hidden only in the sidebar of the window that started the create. Windows now publish their pending VM checkouts to the main process, which shares every window's set with all windows and filters the paired phone's host workspace list and workspace context. The jump palette and the sidebar read the shared set, and a grouped VM project no longer draws an empty-project placeholder while its create is pending. A window's set is dropped when it closes, crashes or reloads. * test(project-groups): reset leaked runtime environment revisions between files * test: remove thin agent-hook and mobile migration suites (#40382) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * fix(vm-recipes): tell paired phones to re-read workspaces when a VM create's pending checkout changes (#40384) The phone filters in-progress VM checkouts only when it reads its host workspace list, so a read made before a window's hide reached the main process kept showing the checkout until the next unrelated change. Emit worktreesChanged for each repo whose pending checkout appears or goes away; phones already re-read their host workspace list on that event. * test: remove agent-hook projections and URL inventories (#40388) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * test: remove low-value agent-hook and row-projection coverage (#40395) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * fix(mobile): stop Review's branch compare re-reading back to back during git bursts (#40278) * fix(mobile): stop Review's branch compare re-reading back to back during git bursts fetchHostQuery re-read a compare as soon as it landed marked by a git event, so a burst of gitStatusChanged events with reads slower than the event spacing kept the desktop running compares back to back, and kept going after Review closed. A re-read now goes at once only after a quiet spell (a write's own event), otherwise floorMs after the last read landed, and stops once Review's build is no longer current. A superseded build no longer evicts the entry a newer build is reading. * fix(mobile): show each compare that lands during a git burst while Review reads it again * fix(mobile): keep note edits when a later compare lands on a shown Review build * test: remove low-value browser, store and adapter suites (#40399) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * test: prune low-value worktree, SSH and activation coverage (#40406) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * test: prune low-value terminal and workspace coverage (#40413) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * feat(speech): run GGUF models on transcribe-cpp with a CPU fallback (#39326) * feat(speech): run GGUF models on transcribe-cpp, falling back to the CPU The speech host child can now load a second engine. A model whose files are GGUF runs on transcribe-cpp (Metal on Apple silicon, Vulkan on Windows and Linux, CPU otherwise); everything else stays on sherpa-onnx, which remains the only engine on Intel Macs. A GPU that fails to load, errors, stalls for 25 s or crashes the process moves the dictation to a CPU-only process (TRANSCRIBE_BACKENDS=cpu) that replays the audio the GPU had not decoded yet, so no words are lost or repeated. A GPU that crashed or would not load is remembered per transcribe-cpp version and OS release, and voice.speechGpu = 'off' keeps it on the CPU. Packaging copies transcribe-cpp, koffi and the target's native package into resources/node_modules outside asar, fails when a target's package is missing, and ships the MSVC runtime beside transcribe.dll on Windows. No catalog model is GGUF yet, so nothing runs on transcribe-cpp until the catalog change that follows. * fix(speech): keep the speech queue running after a failed task, and drop audio frames after a discard * fix(speech): keep the engine's file reads off the main thread's hot paths The engine lookup and the GPU failure marker are read once per process instead of on every dictation start and mobile catalog request, the marker is written asynchronously, and the child reads the hotwords file with fs/promises. The baseline moves the existing engine presence checks from stt-worker-paths to the shared package table and adds the once-per-process marker reads. * test: prune low-value browser WSL and telemetry coverage (#40418) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * feat(mobile): keep a failed dictation's recording and offer Retry (#40276) * feat(speech): dictate through any OpenAI-compatible transcription service (#40160) Add an OpenAI-compatible model whose base URL, model and optional key are set up in a Voice settings dialog and sealed together in ~/.orca, so a key is never sent to a host it wasn't saved for. It reaches OpenAI, Groq, Mistral and local servers, and replaces the unused userModels setting. * test: remove low-value browser, hook and SSH cases (#40423) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * feat(dictation): show committed and in-flight words in the dictation pill (#40428) The pill showed only the current partial and went back to Listening after each final, so pause-committed phrases from transcribe-cpp never appeared. The host's transcript fold moves to src/shared and the desktop pill uses it too: committed text in the foreground, tentative text muted. * test: remove redundant browser matrices and SSH inventories (#40429) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * feat(settings): add a Use GPU switch for on-device dictation (#39466) * feat(settings): add a Use GPU switch for on-device dictation On by default (Auto: the GPU when it works, the CPU when it fails). Turning it off keeps the transcribe-cpp speech process on the CPU, for machines whose GPU driver freezes or restarts them. The row shows when the selected model runs on transcribe-cpp. * fix(speech): reload the warm speech model when Use GPU changes A loaded recognizer kept the GPU choice it started with, so turning Use GPU off left the next dictations on the GPU until the model unloaded. * fix(speech): reload the speech model after a dictation when Use GPU changed during it A recognizer still in use when Use GPU changed stayed loaded afterwards with the old choice. It now unloads as soon as its last dictation ends, and the warm-up loads it again with the new choice. * test: remove low-value terminal, browser-session and SSH cases (#40433) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * perf(mobile): show accounts from the last snapshot (#40425) * perf(mobile): show accounts from the last snapshot * fix(mobile): never count a stored accounts snapshot as live * test(mobile): pin when accounts usage counts as live * fix(mobile): date accounts reads by when they were sent and block switches until live * fix(mobile): show accounts usage only from this screen's own read, drop replies from before a reconnect * feat(mobile): save the chat when the app leaves the foreground (#40417) * feat(mobile): save the chat when the app leaves the foreground A swipe-kill from the app switcher can end the app before the page is hidden: iOS fires visibilitychange only at background, and Android Recents leaves the activity resumed. The shell now sends an appInactive frame on iOS inactive and Android window blur, to pages that declare they read it, and the page saves any chat rows the store doesn't hold yet. * fix(mobile): keep the leave callback out of render * fix(mobile): notice a changed middle row before skipping a chat save * test: remove low-value locale, automation and settings cases (#40437) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * feat(mobile): keep dictating after leaving the session, with a floating pill (#40421) * feat(mobile): keep dictating after leaving the session, with a floating pill * feat(mobile): translate the dictation pill and its toasts * fix(mobile): type away words without claiming the terminal, and keep the pill above screens * fix(mobile): float the pill above bottom bars, reopen the owner's own screen, and tell a refused start wherever you are * fix(mobile): float the dictation pill above the source control bar * fix(mobile): keep pill state out of the host context and reopen the starting screen first * refactor(mobile): subscribe the pill only while it shows and trim the session dictation hook * fix(mobile): key bar clearances by symbol * feat(speech): move the speech models to transcribe-cpp and offer an update for old downloads (#39468) * feat(speech): move the speech catalog to transcribe-cpp models Parakeet v2/v3, Whisper tiny and SenseVoice now download their GGUF builds, which run on transcribe-cpp everywhere, Intel Macs included (on the CPU). A model still holding its old sherpa-onnx download shows "Update to the faster version (<size>)"; updating replaces the old files, and dictating before then says the model needs that update. The five models with no GGUF build are retired and their users moved over: the Japanese Parakeet, the Chinese-English Zipformer and the Paraformer to SenseVoice, and the Korean and Chinese streaming Zipformers to the new Nemotron 3.5 (28 languages). Nemotron's locale codes (ko-KR) are matched from the ISO language setting. * feat(speech): offer the speech model update once after the engine change A card in the notification corner tells people whose selected on-device model needs the new download, or whose retired model was replaced, and starts the same download as Settings > Voice. After a replacement it offers to delete the retired model's files. * feat(speech): move retired Korean and Chinese models to SenseVoice and offer Whisper Large v3 Turbo On transcribe-cpp 0.4.1 with Metal, SenseVoice beat Nemotron 3.5 on Korean and Chinese FLEURS clips, so the retired Korean and Chinese streaming Zipformers now move to SenseVoice. Whisper Large v3 Turbo (Q8_0, 886 MB) joins the catalog as the most accurate choice for Japanese, Korean and Chinese. Nemotron 3.5 stays, described by the languages it does best. * Update README downloads badge (#40440) Co-authored-by: buf0-bot[bot] <252831055+buf0-bot[bot]@users.noreply.github.com> * perf(github): answer phone PR lookups from the desktop's last result (#40430) * perf(github): answer phone PR lookups from the desktop's last result * fix(github): order last PR outcomes by lookup start sequence * fix(github): keep reused phone PR outcomes out of the refresh observers * fix(github): reuse a fallback-found PR only for the same fallback number * test: remove low-value CLI, settings and shortcut suites (#40441) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * refactor(speech): remove sherpa-onnx (#39473) transcribe-cpp is now the only on-device engine on every platform, so the sherpa-onnx packages, their packaging (extraResources, the darwin libonnxruntime prune, the native-variant assert and the Linux libstdc++ exemption), the sherpa recognizer in the speech process and the per-model engine choice all go. Hotwords are written as plain terms. * test: remove low-value CLI and renderer inventories (#40445) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * feat(runtime): tell phones when the desktop refreshes a PR (#40438) * feat(runtime): tell phones when the desktop refreshes a PR * fix(runtime): name every checkout a coalesced PR read stood for * fix(runtime): don't count a read that couldn't load checks as a checks change * feat(speech): spell dictated code terms with a personal and per-repo dictionary (#40450) * feat(speech): spell dictionary terms in dictation, with repo terms and Whisper prompt * test(speech): pin host repo terms for phone dictation * fix(speech): keep symbol terms whole, accept null setup params, resolve SSH repos * refactor(speech): key transcript words once and type phone terms at the reply schema * refactor(speech): merge speech-types imports in the speech IPC * test: remove low-value suites and redundant examples (#40457) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * fix(speech): keep words spoken while the model loads (#40454) Stopping a CPU dictation closed the renderer's audio port while frames still waited behind a decode in the speech worker; the close ended the stream at once and the queued frames were dropped. A close after 'end' now leaves them to decode. A model slower than 30 s to load also lost the start of the dictation, since the renderer kept only 30 s of startup audio; it now keeps as much as the host waits for the load. * fix(dictation): match the pill's Chinese and Japanese phrases to the inserted text, and space Korean ones (#40455) * fix(dictation): join Chinese and Japanese phrases without a space, and space Korean ones The shared transcript fold joined every phrase with a space, so the pill and phone replies showed Chinese and Japanese text with spaces the inserted text doesn't have. It now joins with the same rule as insertion. That rule treated Hangul like Chinese and Japanese, so Korean phrases were inserted with no space between sentences; Korean spaces words, so Hangul now spaces like Latin text. * fix(dictation): don't space after Chinese and Japanese full-width punctuation * fix(dictation): join retried phrases with the same spacing rule * fix(dictation): escape the spacing rule's non-ASCII marks for the orcad bundle The shared fold now pulls the spacing rule into the orcad server bundle, which must stay ASCII. A rich-draft test pinned Hangul joining without a space; it now expects the Korean spacing. * Improve project group ordering across hosts (#39816) * Improve project group ordering across hosts * fix(project-groups): restore each group order after a failed drop A deleted group made the aggregate rollback stop early, leaving other groups at the ranks from the failed drop. Restore each group independently and log the swallowed single-update failures again. * refactor(main): give project group RPC methods their own module Keeps repo.ts under the 300-line cap as the project group surface grows. * test: remove low-value browser, CLI and budget checks (#40459) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * fix(i18n): preserve web runtime error details (#40267) * fix(web): preserve runtime failure details * fix(i18n): update chat behavior settings hint * feat(speech): commit dictation text at each pause with Silero VAD (#39378) Offline models write out the speech before each pause while recording goes on. Short noises and slow window-padded decodes are held off the pause cuts, a VAD error falls back to bounded chunks, and slow phrase decodes are judged per dictation against the time spoken. The VAD download carries legacy files and fetches after any GGUF model. * test: remove low-value CLI, browser and E2E checks (#40466) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * Show the setup-script choice instead of greying out Create (#40341) * Show the setup-script choice instead of greying out Create With a project's setup script set to "Ask every time", Create stayed disabled until the user picked Run or Skip, but that choice only renders inside the collapsed Advanced section, so nothing explained the greyed-out button. Keep the choice out of the disabled gate (as the gate's own comment already intends) and have Create open Advanced to show it. * Annotate the partial submit fixture cast * Bring the setup choice into view when Create needs it Create now scrolls the Run/Skip choice into the dialog's view and focuses it on every attempt, including when Advanced is already open, and the late-discovered setup path uses the same reveal. A submit that only jumps to an existing pending creation no longer asks for a setup choice. * Reveal the setup choice once per Create attempt The choice clears the reveal request after scrolling and focusing, so a later remount (for example after switching projects) cannot pull focus without a new Create. * Drop a pending setup reveal once the user has chosen Choosing Skip in the moment before the reveal fired could still move focus onto Run, so a later Enter switched the choice. * Save a pasted workspace directory as the path it names (#40347) * Save a pasted workspace directory as the path it names A workspace directory with a leading space (" /Users/me/dev") was saved as typed. Readers treat it as relative, so Orca resolved it inside every registered repository and created an empty " /Users/me/dev" tree in each. Normalize the saved value once where settings are written and loaded, as the leading ~ fix did: leading whitespace before an absolute or home path is dropped, while relative paths and trailing characters stay exact. A value repaired on load keeps its old spelling in history so checkouts under the old root stay visible. The settings field shows the saved value. Co-authored-by: Eng. Mahmoud Bek ElNemer <ElNeMeR70@users.noreply.github.com> * Expand ~\ only where it is a home path; drop type casts * Classify the padded path with the host's own path rules On macOS and Linux a leading backslash is part of a relative name, so only Windows treats \work as absolute. --------- Co-authored-by: Eng. Mahmoud Bek ElNemer <ElNeMeR70@users.noreply.github.com> * fix(i18n): translate browser password prompts (#40446) * fix(i18n): translate browser password prompts * fix: wrap localized password save actions * OpenCode subagents show in Chat UI and keep a chat open while they run (#40141) * fix(native-chat): show OpenCode subagents and keep a chat open while they run OpenCode reports each subagent as a child session when the client opts in. Orca now opts in, files each child's tool calls and replies under its own subagent, and keeps the subagent open until the child reports that it completed, failed or was interrupted, including after the parent turn ends. Co-authored-by: SeaBee <85791528+seabee33@users.noreply.github.com> * fix(native-chat): keep a subagent's tool context when its rows are read back from the journal Co-authored-by: SeaBee <85791528+seabee33@users.noreply.github.com> * fix(native-chat): a Stop also ends running OpenCode subagents, and each subagent can be stopped from the strip Co-authored-by: SeaBee <85791528+seabee33@users.noreply.github.com> * fix(native-chat): only a chat Stop closes OpenCode subagents, an early subagent Stop stays available, and the close request has a deadline Co-authored-by: SeaBee <85791528+seabee33@users.noreply.github.com> * fix(native-chat): a subagent Stop that the subagent confirms while the request is out reads stopped Co-authored-by: SeaBee <85791528+seabee33@users.noreply.github.com> * refactor(acp): close child sessions from the agent connection Keeps the session runtime under the line limit after the main merge. * test(acp): read a child command through a type guard * fix(native-chat): a subagent that reports its ending reads stopped even when the close request fails A child Stop's session/close now asks the agent to drop the call on timeout instead of withdrawing the write. * test(native-chat): OpenCode subagent calls group with other agents' subagent calls --------- Co-authored-by: SeaBee <85791528+seabee33@users.noreply.github.com> * fix(native-chat): honor Windows environment overrides consistently (#40301) * fix(native-chat): apply Windows environment overrides consistently Use the same case-aware composition for native chat launches, preflight, model discovery and naming. Canonicalize configured Windows names before account readers and preserve account pins and POSIX case distinctions. Tracked in #39075. Co-authored-by: 김태겸 <oharapass@gmail.com> Co-authored-by: Vitalii Kulish <mancunianez@gmail.com> * test(native-chat): cover effective Windows catalog changes * test(native-chat): retain child environment test import after sync * test(native-chat): verify Windows child environment precedence --------- Co-authored-by: 김태겸 <oharapass@gmail.com> Co-authored-by: Vitalii Kulish <mancunianez@gmail.com> * Source Control's Codex model menu lists your account's models even when Codex's catalog is large (#40117) * Source Control lists Codex models from app-server model/list instead of debug models The Codex text-action picker read 'codex debug models', a dump of Codex's whole catalog with prompt templates (40-90 KB per model). Once it passed the 4 MiB output cap discovery failed and the picker kept Orca's built-in list, and the dump's hidden entries were selectable. List models with app-server model/list (hidden rows excluded), over Source Control's own launch, lock and teardown, with the same 4 MiB input budget and 60 s deadline. * Bound Codex model discovery input in bytes, key its cache case-insensitively on Windows, and stop the app-server only when it ignores stdin EOF - Count raw bytes from both streams against the 4 MiB budget. - Read CODEX_HOME (and other account dirs) case-insensitively on Windows for the host cache key. - Skip the post-listing kill when the app-server already exited; fail waiting listing requests once discovery settles. - Report an incomplete model list as such. - Tests: fake-timer grace and successor admission after a successful listing, method-not-found and unreadable-page fallbacks. * Key the Codex discovery cache on the env spelling Windows spawn uses Windows env names ignore case and Node's spawn takes the lexicographically first spelling, so CODEX_HOME wins over codex_home; the cache key now picks the same one. * Narrow Codex app-server records with the provider record guard instead of type assertions * Read Source Control action model picks under the repo's host key, as the picker saves them Local repos resolved generation under the 'unknown' host key because their connection id is undefined, so the saved pick was skipped and the agent default ran. * Key Source Control model picks by connection until the repo record loads, and test with a real local repo * Key a native Codex listing's cache on process.env when no agent env was resolved * feat(speech): record each model's languages, licence and measured error rates in the catalog (#40431) Error rates come from Orca's speech bench (transcribe-cpp 0.4.1, Metal, pinned GGUFs): LibriSpeech for English, 5 FLEURS dev clips for de, es, fr, ja, ko, pt, ru, tr and zh. speechModelQuality turns them into the Voice settings word scale. * fix(speech): let a slow on-device finish run while the engine still answers (#40460) * fix(speech): let a slow on-device finish run while it still returns text The stop timeout counted 60 s from Finish however much audio the engine still had to decode, so a CPU model on a busy machine failed a dictation it was still transcribing. It now fails only after 60 s without text for that dictation. * fix(speech): count any engine answer as progress while a dictation finishes * fix(mobile): close the details card when you touch the terminal (#38823) * fix(mobile): close the details card when a touch lands outside it Co-authored-by: zhangxaochen <3416677+zhangxaochen@users.noreply.github.com> * fix(mobile): explain the pointerdown listener and drop a focus check that can't fail --------- Co-authored-by: zhangxaochen <3416677+zhangxaochen@users.noreply.github.com> * feat(dictation): pulse three dots in the pill while spoken words are still on their way (#40443) * feat(dictation): show pending dots while the engine holds speech it hasn't committed The VAD pause segmenter already knows when a phrase is open. The recognizer now posts speech-pending when a phrase opens and clears it once that phrase's text is posted, and the desktop pill shows three dots after the text while it is on. Only pause-cut on-device streams send it, so cloud, the paired web client and phones keep today's pill. * fix(speech): keep a lone click from turning the pending dots on * perf(native-chat): addressed tab-map transitions for chat membership (#40098) * perf(native-chat): project structured chat tabs per workspace bucket The shared chat-tab list was keyed on the whole unifiedTabsByWorktree identity, so every tab write anywhere (terminal title batches included) rescanned all tabs and handed every consumer a new list. Rebuild only the buckets whose identity changed and return the previous list while no chat tab changed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * perf(native-chat): reconcile chat status membership per changed tab The status bridge rebuilt every member and host group and captured every chat on any tab-map or owner-input change, and recaptured every chat on any launch notification. Membership now updates only the tabs whose identity changed; owner-input changes re-resolve only unstamped tabs, the only ones whose host depends on them; launch notifications name their session so only its tabs are recaptured (unaddressed ones still recapture all). The sleep and launch-directory companions of one projection land in one store write. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * chore(ratchets): guard whole tab-map triggers and hot-map listeners Add a count ratchet for identity comparisons of the whole unifiedTabsByWorktree/tabsByWorktree map in renderer code (counts may only fall), wired into pnpm lint, run-ratchets discovery and changed-check selection. Extend the advisory no-whole-hot-map-selector rule to inline store listeners that compare a whole hot map and to effect bodies that use one whole from getState(). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * revert(lint): drop the hot-map listener/effect extension The guard stays scoped to the repaired seams; no repository-wide rule change. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(native-chat): capture chat status on semantic tab changes; address tombstone retirement Focus, preview and order-only tab writes no longer recapture a chat's status: membership and the projection fences compare the fields the projection reads. Absent-tombstone retirement now names the sessions it retired, so no launch producer sends an unaddressed notification. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat(store): keyed-record transition seam for tab maps and companion records Writers build next tab buckets and keyed companion records through replaceTabBuckets / replaceRecordEntries (or name the keys of a record they already built), which record exactly which keys and tab IDs changed against the produced record. Readers ask readTabMapChanges / readRecordChanges for an addressed delta; any unannotated link reads as a full resync. Adds subscribeTabTransitions and a store-observer installer registry. The chat-tab list and the status bridge now consume addressed deltas and keep the whole-list walk only as the cold path. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat(store): annotate every shared tab-map writer through the seam Shared tabsByWorktree/unifiedTabsByWorktree writers (tab, editor, browser, worktree, ssh, terminal create/close/navigation/title-batch/reconnect/ hydration, web-session mirroring and layout frames) now build or annotate their next tab buckets and companion records with the exact workspace and tab IDs they changed; full hydration, full frame builds and reconnect inventories are named full resyncs. Writers that copied every bucket for one tab (preview promotion, dirty-file preview clear, worktree removal filters, sleeping-record identity rename) now keep unchanged buckets. Replace the renderer-wide tab-map comparison ratchet with a narrow seam guard: the repaired consumers may walk a whole tab map only in named cold paths, and the pinned writer modules may not build raw seam records. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * chore(store): name seam fields once; type seam records; record moved respawn writes Writers stop repeating tracked field names (centralized in seam-record-fields.ts), the seam takes a named KeyedSnapshot record type instead of casts, and the layout-writer baseline records the respawn helpers moved unchanged out of worktree-layout-lifecycle.ts. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * chore(store): drop seam field cast; record the seam field list in the layout-writer baseline Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(native-chat): keep chat-tab list in source workspace order (C3/F1) Every source workspace keeps a projection slot, even without chats, and the seam reports when a write added or deleted a workspace key or moved a surviving bucket, so the incremental list never reorders first-match consumers; those transitions take the cold rebuild. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(native-chat): keep projection and retirement debt awake (C2, F3) A member is owed from attach or semantic change, members without a host feed keep their own debt, and every reconciliation drains existing owed or retired work even when no new member changed, including a closed last chat whose feed is gone. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(store): stop inferring host-mirror companion IDs from visible tabs (C1) A host retraction can delete PTY or layout records for tabs neither inventory lists, so the mirror funnel marks its tab-keyed records full resync instead of advertising an incomplete addressed set. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * chore(ratchets): close indirect paths in the tab-map seam guard (C4) The guard now rejects ordinary callers of the bridge cold path, value imports the repaired consumers have not reviewed, and raw seam records built into a local binding without a seam helper annotating it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * test(native-chat): drive real tab actions through the status bridge (F2) Close, session rebind with a late old-session tick, and a legacy owner change, through createUnifiedTab/setTabLabel/closeUnifiedTab, so the addressed reconciliation path is exercised. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * chore: exempt seam field-name constants from the layout-writer ratchet; drop dead setters (F4) The seam's SEAM_*_FIELDS lists name fields without writing them, so the ratchet skips them and the raised baseline row is gone (renderer total 569, main 571). setStructuredChatSleptAt and the two launch-directory setters lost their last callers to the batched companion write. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat(store): Map provenance and source-ordered change keys in the seam (PR A addenda) replaceMapEntries gives Map-typed fields (runtimeStatusByEnvironmentId) the same weak provenance and readRecordChanges protocol. Change keys compose forward through a chain, oldest write first, so added keys come out in source order (index keys first for records, as Object.keys orders them). A surviving key deleted and re-added, in one write or across a chain, and a record builder that moves a surviving key, read as a 'reordered' full resync. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(store): writers declare key order; seam reports ordered additions (N1c, N1a) The seam no longer scans both records to rediscover order on every annotation. replace* helpers know insertion order by construction; annotate* takes a declared order ('appended' by default, 'reordered' for a builder that moves keys, read as a full resync), verified only under test. Addressed changes now report keys, source-ordered added keys and deleted keys, so a reader holding its own key ranks places changes in O(changed). Worktree removal declares its editor-transfer records reordered. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * perf(native-chat): scope the chat-tab projection to chat-bearing workspaces (N2c) The projection keeps chat subsets only for workspaces that have chats, plus per-workspace source ranks that change only when a workspace is added or deleted. A focus, label or title write costs O(that workspace); the ordered list is materialized lazily, only for full-list readers, and keeps its identity while no chat changed. Workspace adds and deletes are addressed through the ranks instead of a cold rebuild. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * chore(ratchets): resolve aliases and require annotation before publication (C4) Any reference to a cold helper or Object enumerator outside its named callers counts, including aliases and callbacks; writer values are followed through local aliases and must be annotated before the write that publishes them. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * test(native-chat): scoped hydration keeps the warm chat list equal to a cold read (D1) Drives the real scoped hydrateTabsSession on early/later chats of one session: source order, list order and first-match precedence match a cold rebuild, including when the selection order differs from hydrated order. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * perf(native-chat): cache the chat-workspace order across chat edits (D1 item 5) The lineage keeps chat-bearing workspaces in rank order and only inserts or removes one when it gains its first or loses its last chat; a chat object change re-flattens the list without re-sorting. Full resyncs rebuild it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * chore(ratchets): the seam guard recognizes only construction helpers and cold marks (D1) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * refactor(store): addressed provenance only from constructing helpers (D1) Remove annotateRecordReplacement/annotateTabBucketReplacement and their caller-declared order: only replace*/recordDraft/tabBucketDraft, which perform the construction, derive changed keys, additions and deletions from their operations (delete-then-reinsert reads as reordered); opaque reconstructions use markFullResync. Every former annotate caller is migrated: ordinary local writes build their records once through helpers or drafts with today's operations and order; scoped tab and terminal hydration, the reconnect inventory, host-mirror application and layout flush are full resyncs. Change readers move to keyed-record-change-reads.ts. Renderer layout-writer total 567 (main 571). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * test(native-chat): type the hydration fixture without a cast Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(store): seam record writes define own entries, even __proto__ (N5c) replaceRecordEntries and drafts assigned through the inherited __proto__ setter, so a tab id '__proto__' lost its own PTY, layout and startup entries. Both now define an own data property, as the computed-key literals they replaced did; contract test included. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * perf(terminal): build each createTab record once (N4c) createTab took ensureGroup's and insertSplitGroup's whole records and the orphan cleanup's seam records, then rebuilt them through the seam. It now takes the per-worktree group and split results and gives the orphan cleanup only the bucket it reads, so every seam record is constructed once with its ordered operations. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * chore(ratchets): record createTab's orphan-cleanup input view (renderer total 570, main 571) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * refactor(terminal): split orphan cleanup so createTab cleans only companion caches (N6c) buildOrphanTerminalCompanionCleanupPatch holds the per-tab cache, tab-bar order and selection cleanup; buildOrphanTerminalCleanupPatch adds the seam record deletes on top, unchanged for reconciliation. createTab calls only the companion part with real state and deletes the seam entries through its single construction, so the stub input view and its layout-writer baseline rise are gone (terminal-tab-creation.ts back to 10). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * perf(terminal): filter the orphan cleanup's kept bucket once (N7c) The full cleanup filters the workspace's tabs once and hands the kept bucket to the companion part, which takes its replacement active tab from it; createTab's companion-only call still makes its single find pass. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(tabs): keep removed worktrees' group entries deleted on removal The second emptied-group collapse in removeWorktreeLayout also visited removed worktrees and wrote their deleted groupsByWorktree entry back as an empty list, a delete-then-set the seam read as a reordered full resync. It now visits only surviving workspaces, so removal stays addressed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * chore(tabs): closeEmptyGroup collapses through the shared builder again collapseGroupLayout takes the record builder, and the renderer passes the seam's replaceRecordEntries, so the per-worktree collapse publishes with provenance without new counted layout writes (tabs-group-actions back to 12). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * chore(tabs): reconciliation names its draft fields once (2 + 4 <= 9) The written-field sets come from SEAM_ field-name constants instead of string literals, so the reconciliation split no longer raises the combined layout-writer count (tabs-reconciliation 2, tabs-reconciliation-batch 4, against the original 9). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * chore(tabs): publish reconciliation drafts with explicit field writes (N9c) Revert the SEAM_ field-name constants: the drafts are held under their own names and finishReconciliationDrafts publishes each written draft as an explicit unifiedTabsByWorktree/groupsByWorktree/activeGroupIdByWorktree/ layoutByWorktree property, so the counter sees every real write and the split totals 2 + 4 against the original 9, with no exemption. 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(i18n): avoid gendered review labels in Spanish (#40442) * test: remove low-value speech, sidebar and composer checks (#40470) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * feat(tab-group): make the split pane landing rows outline buttons (#40469) * Show AskUserQuestion option previews on desktop and phone (#40109) * Show AskUserQuestion option previews on desktop and phone Claude can attach a preview (a mockup or snippet) to each option of a single-select question. Orca dropped it, so users chose between bare labels. Options now carry the preview through the journal, terminal asks and the phone, and the question card shows the selected option's preview as plain monospace text. Questions with previews confirm explicitly instead of auto-advancing, so the preview stays readable. * Keep phone previews bounded and digit focus on the named option Phone previews get a capped height with their own vertical scroll, and opening one never scrolls past its top. A digit always focuses its row before the chosen-row check, so Enter confirms the option the user named. Tighter preview line height, a stable phone row root, and a persistence test whose expected previews come from the fixed input. * Narrow the reopened question with a type guard instead of a cast * Keep Claude background tasks attached to their subagent after restart (#39958) * Keep Claude background tasks linked to their subagent across restarts * Keep task ownership scoped to each Claude invocation * Keep partial task events scoped to their invocation * Distinguish pending task facts from admitted invocations * Wait for saved task ownership before interpreting Claude events * Verify journal binding order and saved task liveness * Keep owned task updates from reopening Claude root turns * Exercise owned historical notifications with provider identity * Show friendly advice for Codex turn failures (#39959) * Show friendly Codex turn failure advice * Match terminal failure callback to status row type * Keep terminal diagnostics in Details and clarify unknown failure advice * Preserve usage-limit diagnostic metadata * Validate custom host advice in phone renderer fixture * Check categorized compaction failures and retained diagnostics * Complete localized model-unavailable notices * test(mobile): keep the failure notice helpers main's test cleanup removed * Use Claude CLI titles for default native chat naming (#40069) * Reuse Claude CLI titles for default chat naming * Preserve independent naming while fencing Claude title reuse * Keep optional title account lookup from blocking chat naming * Clarify deferred preparation in naming tests * Bind first chat naming to its ready handover * Exercise title cleanup through a real queued command * Use the timestamped operation fixture for compaction * test: exercise naming fallback through Send now * test: exercise terminal naming fallback after final starts * test: remove low-value mobile and attachment cases (#40475) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * fix(chat): always show copy and fork under a finished agent turn (#40474) * fix(agent-status): show Codex's mid-turn async question as waiting for the user (#39087) * fix(agent-status): show Codex's mid-turn async question as waiting for the user * fix(agent-status): keep Codex's async question waiting on paired hosts under its working title The phone's PTY-title renewal turned the waiting row back into working, because Codex keeps its working title while the question waits. * fix(agent-status): clear Codex's open async questions when the user sends a plain message Orca's chat card answers an async question as a quoted message, not Codex's reply wrapper, so the pane stayed waiting until the turn ended. * refactor(agent-status): move the legacy status test seed out of listener-state * feat(settings): redesign Voice settings around a setup card and a rated model list (#40452) * fix(speech): keep a slow GPU model load on the GPU while it still makes progress (#40472) The GPU stall watch gave the whole model load one 25 s budget, so a cold disk or busy machine restarted a healthy load on the CPU and could miss the 60 s start limit. The speech process now reports each load step, and the watch restarts on it; a step that hangs for 25 s still moves to the CPU. * Fork Codex replies after rewinding a chat (#40140) * Fork Codex replies from the current history after rewind * Strengthen Codex fork preparation failure coverage * Preserve Codex fork compatibility and original chat guidance * Explain when Codex cannot start for a fork * refactor(claude): move the kill-delivered receipt check out of the session adapter (#40481) The adapter crossed the 300-line cap after #40069 and main's lint fails. The same receipt check ran twice in it; one shared predicate brings the file back under the cap with no behaviour change. * fix(speech): reload the warm recognizer once the VAD download lands (#40477) A recognizer that loaded before the Silero VAD file existed kept cutting text only at stop until its next restart. When the VAD lands, the speech service now unloads that recognizer once no dictation uses it and warms it again, so pause cuts start on first use. A running dictation is never interrupted. * feat(settings): manage dictation vocabulary in Voice settings, per user and per repo (#40471) * feat(settings): add a Vocabulary group to Voice settings for personal and repo terms * feat(speech): use the repo name as a dictation hint without recasing one-word names * fix(settings): use Input and Button styling as the design system defines it * fix(settings): chain quick repo-term edits, report a host that drops them, keep the hint off phone replies * fix(settings): key a pending repo-term write by host too * refactor(settings): catch a dropped repo-term write in updateRepo and keep the name hint out of stored terms * fix(settings): one vocabulary chip per term with its aliases, and no repo suffix on the scope tab * fix(settings): skip a bare vocabulary term that already has an entry * feat(mobile): add Shift, Ctrl and Alt latches and opt-in agent keys to the terminal key row (#38776) * feat(mobile): smart rail keys for the terminal agent's state, with Shift/Ctrl/Alt latches * fix(mobile): cancel key presses only when the key row really moves * fix(mobile): keep Smart rail on through Reset Defaults and finish two-write keys * fix(mobile): only a finger scrolling the key row cancels its presses * fix(mobile): hold the smart group until the tap's press lands, and drop clicks on keys that moved * refactor(mobile): simplify the smart rail touch hook and layout read * chore(mobile): allowlist the Shift, Ctrl and Alt key names * feat(mobile): Codex async question keys on the smart rail * fix(mobile): drop the Codex Always key, whose key differs by approval Codex binds "don't ask again" to p for a command-prefix rule and a for session and file approvals (0.136 through 0.166). The permission hook doesn't say which one is on screen. * test: remove 21 low-value tests and two suites (#40479) * test: remove 21 low-value tests and two suites * test: remove Claude test-only background roster getter --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * test: remove 16 low-value chat tests (#40488) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * test: remove 12 low-value paste and split tests (#40491) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * fix(agent-picker): apply a model or effort picked in a form's setup panel (#40494) * fix(agent-picker): apply a model or effort picked in a form's setup panel * fix(agent-picker): keep the open setup panel when the form takes its pick * fix(agent-picker): keep a form's accepted pick across scope resets and panel close * fix(agent-picker): stage Arguments chip edits and keep picks compiler-safe * perf(agents): release completed helper payloads and avoid history scans (#40171) * perf(agents): release published child payloads and index live work * perf(codex): preserve live task order on membership changes * fix(codex): preserve parent-first helper interruption * test(codex): assert public helper task identities * fix(codex): keep helper roots in original stop order * fix(codex): retain complete live helper ancestry for Stop * Preserve sibling order when reasserting helper ownership * perf(native-chat): keep streaming chats from re-projecting their whole transcript (#40251) * perf(native-chat): keep streaming chats from re-projecting their whole transcript Each stage of the streaming transcript pipeline (reducer merge, question pass and receipts, message projection, desktop list fold) keeps its previous input and output and re-derives only revised or appended rows, falling back to the existing full projection whenever another row could change. Desktop folds through the phone's fold units, now shared, and live trims batch by a bounded slack so appends keep row positions. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * perf(native-chat): reuse appended subagent rows and batched revisions Appended rows in chats with subagent rows extend their turn chunk when earlier turn inputs are unchanged; batch merges and multi-row revisions do one pass each; rows without journal positions keep in-place reuse. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * perf(native-chat): look up subagent chunks once per appended batch Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * test(native-chat): pin the live trim slack Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat(orchestration): mail an agent on a paired server with send --on; its reply comes back by itself (#40106) * feat(orchestration): mail agents on a paired server with send --on, replies come back by themselves * fix(orchestration): gate --on on the carrying Orca, ack retried deliveries, refuse payloads and federated workers * chore(orchestration): annotate peer-mail row casts and drop a wall-clock wait in its test * chore(orchestration): name mail-between-servers codes server_mail_unsupported and mail_requires_server_pairing * docs(cli): list --on in the orchestration reply usage * fix(orchestration): name --environment, the flag on main, in agent mail refusals and the guide * chore(orchestration): mark the two deliberate agent-kind branches mail between servers needs * docs(cli): leave --on out of the reply usage; it is accepted only to refuse it * fix(orchestration): keep peer conversations to peer ids, survive resets and re-pairs, keep pulling on a registry error - A server takes only peerconv_ conversation ids, so a paired computer cannot name another Orca's dispatch in the relay. - A replayed reply after a mail reset is acknowledged, not retried forever; reset tasks keeps replies waiting to be pulled. - A re-paired server starts a new conversation instead of refusing every later send and reply. - A failed registry read keeps the pull loop retrying. - Drop the two ast-grep-ignore lines that only #40193's rule needed. * fix(orchestration): worker-start --on runs on the caller's own Orca, like send --on An inherited ORCA_ENVIRONMENT sent worker-start --on to that server, so the --on command the agent refusal suggests did not work. One rule now keeps send, reply and worker-start with --on on the caller's own Orca. * fix(orchestration): refuse reply --on on both sides of a conversation between servers The side that opened the conversation still took --on when it named the right server; the reply usage says --on is accepted only to refuse it. * feat(native-chat): bring back the New divider behind a setting (#40490) Restores the line above messages that arrived while you were away, the scroll to it on return and the screen-reader announcement, all removed in #38044. A new Chat > Behavior switch, "Mark new messages when returning to a chat" (on by default), turns it off; off tracks nothing. * fix(acp): reset reply digest when a subagent restarts (#40496) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * test: remove low-value chat surface suites and cases (#40495) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * fix(speech): skip a canceled dictation's queued decodes, also during Finish (#40483) * fix(speech): drop a canceled dictation's queued decodes, also during Finish A cancel during "Finishing…" never reached the speech process, and a cancel that did waited in line behind every decode queued before it, so the next dictation sat behind audio nobody wanted. The host now sends the discard during Finish too, and the speech process answers it at once and skips the stream's queued work. * fix(speech): close an audio port whose stream was canceled before it attached * fix(speech): restart the speech process when a canceled decode outlasts a short grace A cancel now answers at once, so a decode already running for the canceled stream (hung in native code, or just long) could hold the queue for the next dictation. The host waits up to 2 s for the speech process to reach the discard; past that, with no other dictation on it, the process restarts, and a dictation starting meanwhile waits for that instead of reusing it. * fix(speech): skip a canceled stream's remaining chunks inside one feed or finish * fix(speech): keep a failed restart after a cancel from failing the next dictation * test: remove 54 low-value chat and terminal tests (#40500) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * test: remove 36 low-value terminal lifecycle cases (#40503) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * fix(automations): reopen a reused automation chat tab in the background (#40271) * fix(automations): reopen a reused automation chat tab in the background An automation that reuses its last chat queued the prompt into that session even after the user closed its tab, but never brought the tab back. After a reused send is accepted (including a lost or refused reply recovered from the run receipt), reveal the session and publish its tab with activate:false so it reappears without taking focus. A publish failure is logged and never undoes the accepted send. Extract the reveal + background publish pair into publishChatTabInBackground and share it with reopenWorkerChat. Fixes #40260 Co-authored-by: Wooseong Kim <innocarpe@gmail.com> * test(automations): use the string workspace id in the chat-reuse harness --------- Co-authored-by: Neil <neil@stably.ai> * feat(mobile): read dictation progress to VoiceOver and TalkBack (#40504) * feat(mobile): announce dictation to VoiceOver through the shell * feat(mobile): speak dictation from the host, so leaving the session and the pill's toasts are announced too * fix(mobile): say dictation outcomes where they are known, and re-read a repeated live message * fix(mobile): leave a setup refusal to its setup sheet instead of reading the raw code * fix(mobile): say cancelled when a kept recording is discarded * fix(mobile): keep the selected GitHub project when switching projects (#39964) * fix(mobile): keep the selected GitHub project when switching projects Picking another GitHub Project on the phone snapped back to the first one. A remembered desktop Board view made the pick throw before it committed, and a committed pick wrote picker rows (title, summary) into settings, which the host's strict schema refused, so the next hydration restored the old project. Commit only identity fields, ask for a view when the remembered one is not a table, keep the candidate project's views out of the active list until it commits, drop late view replies from an earlier pick, and key Browse rows by project identity. Co-authored-by: Eng. Mahmoud Bek ElNemer <tt21913@gmail.com> * fix(mobile): keep github.com implicit in project refs and error on projects with no table view --------- Co-authored-by: Eng. Mahmoud Bek ElNemer <tt21913@gmail.com> * fix(mobile): keep unchanged lines in diffs of large files (#40511) Files past the LCS cell budget fell back to prefix/suffix diffing, so two edits at the ends of a 450-line file showed every line as rewritten. Use jsdiff's Myers diff bounded by edit count for those files, keeping the prefix/suffix fallback for mass rewrites. * feat(browser): simplify the toolbar to one Annotate button and one menu (#40501) Grab, Annotate and Draw become one Annotate split button. DevTools, open in default browser, hard reload, find and extensions move into the menu, with the profile list, new profile and cookie import under Profile. Zoom, viewport size, password offers and file actions show as chips inside a flat address field, and the Import hint moves to the new tab page. The row drops from 50 to 40 px and the fold from nine stages to two. * fix(claude): isolate new launches from parent sessions (#40281) * fix(claude): isolate independent launches from parent session environments * test(claude): use supported account environment fixture * docs: slim CONTRIBUTING.md to the essentials (#40272) * docs: slim CONTRIBUTING.md to the essentials for getting a PR merged Move dev-environment reference into docs/development.md and the maintainer release process into docs/releasing.md. * docs: match CONTRIBUTING visual-proof guidance to the PR template * docs: cut dev-environment internals and drop the stale release doc Trim docs/development.md to the setup steps people actually hit, drop docs/releasing.md in favor of the self-documenting Cut Release workflow, and move the RC Homebrew cask into the README. * Document Node compatibility and dev profile cleanup * Offer only the speeds the model lists (#40257) A speed the chat reports that no model lists, in practice Flex from the user's own Codex config, is no longer added to the Speed choices. It still runs and is still sent. A chat with no model of its own keeps its saved speed when some model lists it, so Standard can still turn it off. * fix(mobile): keep a finished agent tab's icon when its name mentions another agent (#40513) * fix(mobile): stop reading a tab's name as its agent's terminal title The host publishes a terminal tab's name (custom name, quick-command label or agent session name) in place of its live title. Mobile fed that name to the shared tab-agent resolver as title evidence, so a finished Claude tab named "Agy status bar item" was read as a reused Antigravity pane. Desktop resolves from the raw title and shows Claude. Fixes #40084 Co-authored-by: Wenhao <4804785+Manho@users.noreply.github.com> * fix(mobile): re-render a terminal tab when only its name changes --------- Co-authored-by: Wenhao <4804785+Manho@users.noreply.github.com> * test: remove low-value terminal coordination and startup cases (#40512) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * fix(i18n): translate sparse preset validation failures (#40277) * fix(i18n): translate sparse preset validation failures * fix: classify sparse directory validation by type * test: remove low-value cold restore and reattach variants (#40522) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * test(browser): reset proxy policy in WebAuthn profile fixture (#40468) * fix(skills): load Orca browser guidance for ordinary web tasks (#39916) * docs: load Orca browser guidance for ordinary web tasks Extend the Orca CLI skill description to include local and external page opening, reading, testing, and captures while working in Orca. Preserve explicitly chosen browser tools and the Computer Use boundary. Regenerate discovery/install bytes and append the new digest. Fixes #39880 * fix: route existing Edge windows to desktop browser control * docs: preserve configured desktop-control tool precedence * docs(skills): scope orca-cli browser trigger to page work and keep the Computer Use rule Drop "reading" so doc lookups stay on fetch tools, say plain HTTP/API calls don't need the skill, and restore the original Computer Use sentence and guide body, which the issue didn't ask to change. * docs(skills): list Edge among existing browser windows in the orca-cli guide The wider page trigger makes "screenshot my open Edge tab" load orca-cli, and the guide named only Chrome and Safari as windows that go to desktop control. --------- Co-authored-by: Kelvin Amoaba <97001695+AmoabaKelvin@users.noreply.github.com> * fix(usage): price Claude Fable 5.2 and Mythos 5.2 (#40506) * fix(agent-hooks): unwrap outer sh -c wrapper when capturing Antigravity hook process (#40153) * fix(agent-hooks): unwrap outer sh -c wrapper when capturing Antigravity hook process * docs(agent-hooks): add docstrings and verify PreToolUse/PostToolUse/PostInvocation shell sequence * test(antigravity): keep outer shell wrapper alive in shell-mode hook test * fix(agent-hooks): require shell wrapper on Darwin and add OSTYPE=darwin unwrap tests * fix(agent-hooks): match the macOS hook wrapper on argv[0] only An agent whose prompt quotes the wrapper (/bin/sh ... ORCA_HOOK_AGENT_PID=) would otherwise report its parent, the pane shell, as the agent. Drops the OSTYPE test seam and keeps the unwrap test at the capture layer only. --------- Co-authored-by: Ivan Ha <info.ivanha@gmail.com> Co-authored-by: Kelvin Amoaba <97001695+AmoabaKelvin@users.noreply.github.com> * style(menus): roomier 26px rows, lighter icons, solid surface Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: m4air <m4air@m4airs-MacBook-Air.local> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Jinwoo Hong <73622457+Jinwoo-H@users.noreply.github.com> Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com> Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com> Co-authored-by: Kelvin Amoaba <97001695+AmoabaKelvin@users.noreply.github.com> Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> Co-authored-by: Justas Brazauskas <brazauskasjustas@gmail.com> Co-authored-by: Victor GALISSON <victor.galisson@purecontrol.com> Co-authored-by: jp-liu <79979500+jp-liu@users.noreply.github.com> Co-authored-by: Dhruv Singal <dhruvsingalabc@gmail.com> Co-authored-by: Neil <neil@stably.ai> Co-authored-by: Manuel Meurer <manuel@meurer.io> Co-authored-by: Haoyu(Jerry) Wu <wuhaoyujerry@users.noreply.github.com> Co-authored-by: Jerry Wu <haoyuwu@andrew.cmu.edu> Co-authored-by: Wooseong Kim <2222333+innocarpe@users.noreply.github.com> Co-authored-by: Franz Felberer <franz@felberer.at> Co-authored-by: Calvin <35207870+zzz163519@users.noreply.github.com> Co-authored-by: Wenhao <manhodl@gmail.com> Co-authored-by: Pr1p <zwq19980411@gmail.com> Co-authored-by: Yeji Han <yeji.hvn@gmail.com> Co-authored-by: buf0-bot[bot] <252831055+buf0-bot[bot]@users.noreply.github.com> Co-authored-by: Sean876-alt <sean@livingstoncaj.com> Co-authored-by: Sean876-alt <224890246+Sean876-alt@users.noreply.github.com> Co-authored-by: Eng. Mahmoud Bek ElNemer <ElNeMeR70@users.noreply.github.com> Co-authored-by: SeaBee <85791528+seabee33@users.noreply.github.com> Co-authored-by: 김태겸 <oharapass@gmail.com> Co-authored-by: Vitalii Kulish <mancunianez@gmail.com> Co-authored-by: zhangxaochen <3416677+zhangxaochen@users.noreply.github.com> Co-authored-by: Eng. Mahmoud Bek ElNemer <tt21913@gmail.com> Co-authored-by: Wenhao <4804785+Manho@users.noreply.github.com> Co-authored-by: Vyacheslav Scherbinin <gentslava@mail.ru> Co-authored-by: briannguyen9489032-beep <briannguyen9489032@gmail.com> Co-authored-by: Ivan Ha <info.ivanha@gmail.com> |
||
|
|
828e5bd0c9 |
fix(kiro): keep the Kiro session when kiro-cli reports status over OSC 7501 (#40568)
* fix(kiro): keep the Kiro session when kiro-cli reports status over OSC 7501 kiro-cli's TUI reports its state over OSC 7501 as `app=kiro-cli`, while Orca's Kiro hooks, resume records and cold restore all use the agent id `kiro`. The projector passed the app id through unmapped, so one Kiro pane was tracked as two agents: - a `kiro-cli` report that followed a finished `kiro` hook row took the row over as a different program and dropped its provider session; - while a `kiro-cli` row was live, `kiro` hooks were treated as a nested CLI and their session id was not recorded. `kiro-cli` is not a resumable agent id, so no resume record was kept and a restarted Orca reopened Kiro tabs as plain shells instead of running `kiro-cli --resume-id <id>`. Map the app id to `kiro`, as `claude-code` and `grok-build` already are. * docs(agent-hooks): list Kiro as an OSC 7501 sender reporting as kiro-cli --------- Co-authored-by: Kelvin Amoaba <97001695+AmoabaKelvin@users.noreply.github.com> |
||
|
|
11eaa914fa |
fix(native-chat): let the first chat in a new worktree send and pick models while it starts (#40912)
* fix(native-chat): let the first chat in a new worktree send and pick models while it starts A message sent while a chat's agent was still starting was refused with a greyed Send and no reason. It now shows as sent at once and goes out with the session create, or right after the chat exists, queued behind an opening turn. New chats now open their model picker from another workspace's list without naming its default instead of a dead "Model" pill. The pending worktree chat re-asks while the host is still listing, falls back to the built-in list on failure, shares its answer with the worktree's chat, and seeds the saved selection so the permission picker shows. The worktree setup card now runs "Start <agent>" once the worktree is ready instead of leaving it pending forever. * fix(native-chat): keep a pending chat's host model list when a later re-read fails |
||
|
|
6b7da572e5 |
perf(persistence): window moves and UI edits no longer re-save the whole profile (#40627)
* perf(persistence): saves name the profile domains they changed UI changes, window moves, SSH terminal exits, phone tab switches and repo/folder/SSH/lineage edits no longer re-serialize and hash the whole profile on the main thread. Each save names its domains (or 'whole' where an operation can't know them), and one per-domain saved form serves both selective and whole saves, writing dependent domains together. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(persistence): keep folder re-tiering and plugin context on named saves Folder workspace unread writes re-tier sort stamps again, and plugins hear an active folder's rename, now that those saves name their domain instead of the whole profile. The folder-note test drains the load's whole save so it checks the named save. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * test(persistence): typed folder workspace fixture for the re-tier case Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * test(persistence): build the serializer from typed state in the parity test Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(persistence): read unprojected domains without a type assertion Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * test(persistence): stall and fail the selective writer UI saves now use Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * perf(persistence): every mutation saves only the domains it changed Removing a project, renaming a worktree's path, re-adopting an SSH target, importing a catalog, deleting a group or folder workspace, retrying a failed terminal close and remapping session panes now name their domains instead of rewriting the whole profile. Only startup load and maintenance resume rewrite every domain, through a separately named entry point a lint rule keeps out of mutation code. A named automationRuns save refreshes a pending run delta so it can't write an older run list. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(persistence): a named automation-run save supersedes older run lists A catalog import replaces the run list while an earlier run write can still be in flight; if that write fails, its restored pending list must not win over the import. Domain lists name the local session through the shared constant so the layout-writer ratchet stays exact. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(persistence): keep the whole-row fallback for replaced run lists A run list replaced outside the run-delta path (catalog import, SSH re-adoption) saves as a whole row again, so histories that can't use the per-run storage still save. A failed in-flight run write restores its pending list only while that list is still current; otherwise it marks the run domain for a whole-row save. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(persistence): save run lists per-run rows can't hold as one row A run delta whose list can't be stored as per-run rows (a legacy history with duplicate run ids) now saves as the ordinary whole-row replacement instead of failing the transaction, so a catalog import or run edit on such a profile still commits. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
05cea5e99d |
test: remove 78 low-value tests across 39 suites (#41012)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> |
||
|
|
1fbc0a5455 | refactor(renderer): import launch and scroll definitions from owners (#41016) | ||
|
|
ef26fd8ea3 | feat(editor): open a file Orca can't display with the default app from its tab (#40971) | ||
|
|
8afd012d69 |
feat(browser): move extensions out of Experimental into Settings › Browser, on by default (#40939)
* feat(browser): move extensions out of Experimental into Settings › Browser, on by default The old experimentalBrowserExtensions key is retired on load so profiles that saved the old false default start with extensions on. * test(startup): mock extension startup in the ready-phase identity test Extensions now default on, so ready-phase startup installs extension support, which this browser-identity fixture's Electron and store fakes don't cover. |
||
|
|
01efbf8cd1 |
feat(mobile): show merged, closed and draft PR icons by state (#40921)
* feat(mobile): pick the PR glyph from PR state Workspace rows always drew the open-PR glyph and only changed its color, and the PR tab's state badge had no glyph. Both now show merged, closed and draft glyphs, from one prStateIcon mapping that the details sheet and task rows also use. * feat(mobile): show the PR state on the session header's source-control button The button always drew a branch glyph. When the worktree's catalog row has a linked PR it now draws that PR's state glyph in its state colour, read from the host list's worktree.ps query in its own component. * fix(mobile): read the header's PR state from the catalog cache only Opening a session must not request worktree.ps before its first paint, so the source-control button reads what the host list last loaded instead of fetching it. |
||
|
|
ee3db6fe8c |
fix(agent-status): a skipped Codex async question no longer stays pending (#41013)
Codex's skip key (Ctrl+]) drops an async question only in its TUI: no hook, no transcript line. Orca kept the question open and the row waiting until the turn ended. The renderer now forwards the skip keystroke as a codexSkip question inference; main drops one question from the tracker and restates the row, returning it to working once none remain. |
||
|
|
dc7e540698 |
fix(agent-status): stop Cursor's tab and sidebar title flickering while it works (#40996)
* fix(agent-status): stop Orca's spinner title fighting Cursor's own title cursor-agent now paints its own '<chat> - ⏳ Working' title, animated every 200 ms. Orca still reasserted '⠋ Cursor Agent' on every Cursor hook and every 80 ms, so the tab and sidebar flipped between the two. Leave the working title to Cursor, as for Codex; Orca still writes the ready and action-required titles. * fix(agent-status): read cursor-agent's own status titles With Orca no longer writing working titles over cursor-agent, every title reader saw Cursor's '<chat> - ⏳ Working' titles as no status, so a Cursor worker stopped taking orchestration mail mid-turn. Parse cursor-agent's exact emoji + label pairs in the shared title classifier; review, loading, cloud and reconnect screens are not a running turn and stay unclassified. * fix(agent-status): keep the Cursor title parser ASCII for orcad bundles esbuild leaves regex literals as written, and orcad rejects a non-ASCII server bundle; escape the emoji instead. |
||
|
|
3e0b7f791a |
feat(pi): offer a thinking level for Pi terminal launches (#41006)
The launcher's Pi panel now shows Pi's thinking levels on the terminal surface, narrowed to what the picked model supports, and a pick starts Pi with `--thinking <level>`. Untouched, Pi keeps its own default. Co-authored-by: lucas-wu-wakakak <8309814+lucas-wu-wakakak@users.noreply.github.com> |
||
|
|
dbd3454ee1 | feat(mobile): GitHub-style diff rows with a pinned gutter and sideways scroll (#40961) | ||
|
|
aba6ec4c4c | feat(mobile): GitHub syntax colours and the system code font for code, files and diffs (#40942) | ||
|
|
dedec14074 | refactor(renderer): group pane layout and terminal input owners (#40989) | ||
|
|
bb1d4789c4 |
fix(pi): start Pi terminal launches on the model picked in the launcher (#41005)
Pi had no launch catalog, so a picked model compiled to no arguments. A launch-only catalog maps it to `pi --model <provider/id>`. A --model in Pi's Arguments stays literal: Pi's CLI fuzzy-matches it, while Pi chats need an exact provider/id. Co-authored-by: lucas-wu-wakakak <8309814+lucas-wu-wakakak@users.noreply.github.com> |
||
|
|
59fd2dac7c |
Remove 181 low-value tests and 28 entire suites (#41007)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> |
||
|
|
ba930a07c1 |
fix(agent-status): show each OpenCode tab's own session, not every busy session in its folder (#41002)
* fix(agent-status): prevent shared-service OpenCode OSC 7501 from marking idle tabs working (#39619) * fix(agent-status): scope OpenCode shared-folder OSC 7501 to the pane's hook OpenCode 2 keys its OSC 7501 records by root sessions and never by child sessions, so drop the parent/child id exception. Keep OpenCode's all-idle report able to settle a hook-silent pane, and move the precedence test to the server layer. * fix(agent-status): keep another OpenCode session's status off a hooked pane OpenCode's OSC 7501 root summarizes every session sharing the folder's tabs, so its block or title on an OpenCode hook row belongs to another pane. The pane's own prompts already come from Orca's plugin. * refactor(agent-status): decide OpenCode peer records from the root app --------- Co-authored-by: Eng. Mahmoud Bek ElNemer <tt21913@gmail.com> |
||
|
|
313edfe375 |
fix(orchestration): a worker whose terminal died with Orca can be reopened again (#40963)
* fix(orchestration): a worker whose terminal died with Orca can be reopened again When Orca dies while a terminal worker's follow-up is reopening, restart recovery proves the worker's terminal exited and retires it, but left the pane's restored hook row naming the conversation. Agents that report no process to probe (Grok) then refused every later follow-up as held elsewhere. Recovery now ends that pane's agent status, as the PTY's own exit would have. * fix(orchestration): leave a hook row a newer terminal in the pane owns |
||
|
|
15b4b1eb02 |
fix(orchestration): a chat worker that died with Orca can be stopped and followed up after restart (#40967)
Restoring orchestration at startup reconciled terminal workers but not chat workers' sessions. On a headless server (and orcad) nothing else did, so a chat worker killed with Orca kept its old lease and read as unverifiable: its open Dispatch could not be stopped, and mail to it was only filed. Restoring orchestration now reconciles chat restart leases first, as the desktop window already does at startup, so the worker reads as exited and behaves as one whose process died while Orca ran. |
||
|
|
b89ee4db71 |
fix(orchestration): say the pairing is gone when a worker's server was removed (#40949)
* fix(orchestration): say the pairing is gone when a worker's server was removed worker-show, stop and release on a Dispatch from an earlier pairing failed with the environment store's raw "Unknown environment: <id>". Resolving the server a worker is pinned to now answers peer_changed with a message that the saved environment was removed or re-paired, as it already does when the same environment names a different server. * fix(orchestration): map only a missing environment to peer_changed |
||
|
|
8ef629becd |
test: remove 129 low-value definitions and four whole suites (#41000)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> |
||
|
|
81d3091515 |
test: remove 130 low-value definitions and eight whole suites (#40997)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> |